splitio / ruby-client Goto Github PK
View Code? Open in Web Editor NEWRuby SDK client for Split Software
Home Page: https://split.io
License: Other
Ruby SDK client for Split Software
Home Page: https://split.io
License: Other
I am encountering the following error consistently in the logger:
Splitio: #<IOError: stream closed in another thread>
After adding a feature which requires inspecting the traffic_type for each split, we noticed a significant spike in our response times.
We tracked it down to this change:
irb(main):024:0> Benchmark.bm {|x| 10.times { x.report { Adapters::SplitAdapter.new.send(:split_manager).splits } }}
user system total real
0.080000 0.028000 0.108000 ( 0.404583)
0.088000 0.028000 0.116000 ( 0.400634)
0.080000 0.048000 0.128000 ( 0.417616)
0.068000 0.044000 0.112000 ( 0.406767)
0.068000 0.040000 0.108000 ( 0.397871)
0.072000 0.068000 0.140000 ( 0.412072)
0.080000 0.036000 0.116000 ( 0.392635)
0.080000 0.048000 0.128000 ( 0.390702)
0.092000 0.036000 0.128000 ( 0.414035)
0.084000 0.048000 0.132000 ( 0.459113)
irb(main):025:0> Benchmark.bm {|x| 10.times { x.report { Adapters::SplitAdapter.new.send(:split_manager).split_names } }}
user system total real
0.008000 0.000000 0.008000 ( 0.013941)
0.004000 0.000000 0.004000 ( 0.011022)
0.008000 0.000000 0.008000 ( 0.013846)
0.008000 0.000000 0.008000 ( 0.011736)
0.000000 0.004000 0.004000 ( 0.010728)
0.004000 0.000000 0.004000 ( 0.011632)
0.008000 0.000000 0.008000 ( 0.011978)
0.004000 0.000000 0.004000 ( 0.010795)
0.012000 0.000000 0.012000 ( 0.014070)
0.004000 0.000000 0.004000 ( 0.012502)
I noticed this line seems to be rather costly. Is there a less costly way to determine traffic_types?
We've noticed after upgrading from 7.2.2 to 7.2.3 we're experiencing performance issues. Our test suite grinds to a halt after a few seconds. Memory leak maybe?
I've forked and can take a closer look at the diff between the versions but wanted to open an issue before I did.
When a split/treatment is not defined or worse, when things go bad and Redis is down... control
is the default treatment returned. For us, it made more sense to do excluded
since this is an A/B throw away group convention. See: http://www.databoxdigital.com/2013/09/12/a-common-AB-testing-mistake/
To achieve these results, our wrapper gem for splitclient-rb
makes the following change.
if Kernel.respond_to?(:silence_warnings) # Ruby 2.4 and up.
silence_warnings do
SplitIoClient::Engine::Models::Treatment::CONTROL = 'excluded'.freeze
end
else
begin
old_verbose = $VERBOSE
$VERBOSE = nil
SplitIoClient::Engine::Models::Treatment::CONTROL = 'excluded'.freeze
ensure
$VERBOSE = old_verbose
end
end
This is not an issue, just a communication that I thought it was really cool this gem used a constant which allowed us to freedom patch some things. Just wanted to share this and see if it solicited any thoughts or feedback. Thanks!
When we tested Split.io in standalone
mode, I believe Redis going down caused get_treatment
to not raise exceptions and return excluded. I could be wrong about this because as of now, we run the Go synchronizer and hence the Ruby apps are in consumer
mode. Under this mode when the Redis connection goes down, any page that uses get_treatment
will error out.
Our wrapper gem solves this by rescuing Redis::BaseError
and returning SplitIoClient::Engine::Models::Treatment::CONTROL
. To be fair, we never really had Redis go down and we do have our Split Redis AWS instance setup in such a way that we feel pretty confident about it being there for us. That said, just wanted to share this pattern and ask if there was anything more we could do on our end. Thanks in advance!
By default, the SDK logs out to STDOUT. This can be very distracting and noisy when a developer starts a rails console session or when running tests. The SDK should detect these run modes and configure the default logger to be silent, or redirect to the Rails logger instead of STDOUT.
Here's a snippet of what I do in my split configuration.
options = {}
options[:logger] = NullObject.new if defined?(Rails::Console) || Rails.env.test?
...
SplitIoClient::SplitFactory.new(api_key, options)
Note: It's unfortunately that I have to explicitly pass in a NullObject
which is not standard in Ruby. Perhaps the options parser should distinguish between passing in an explicit nil
vs not configuring the value.
While configuring splitclient-rb
for an existing application, I've bootstrap SplitIoClient
following the available documention:
require 'splitclient-rb'
options = {block_until_ready: 3}
split_factory = SplitIoClient::SplitFactoryBuilder.build("YOUR_API_KEY", options)
when instatiating the client I'm getting the following error:
ERROR -- : Failed to make a http request
INFO -- : Starting metrics service
ERROR -- : [splitclient-rb] Unexpected exception in store_splits: #<NoMethodError: undefined method `[]' for nil:NilClass> undefined method `[]' for nil:NilClass
/bundle/gems/splitclient-rb-4.1.0/lib/cache/stores/split_store.rb:45:in `store_splits'
/bundle/gems/splitclient-rb-4.1.0/lib/cache/stores/split_store.rb:35:in `block (2 levels) in splits_thread'
/bundle/gems/splitclient-rb-4.1.0/lib/cache/stores/split_store.rb:34:in `loop'
/bundle/gems/splitclient-rb-4.1.0/lib/cache/stores/split_store.rb:34:in `block in splits_thread'
INFO -- : Starting impressions service
WARN -- : uninitialized constant FaradayMiddleware::Gzip
If you look at the last line of the log, a warning is raised by Faraday
saying that it doesn't know what is FaradayMiddleware::Gzip
. NOTE: if you don't provide options
to SplitIoClient::SplitFactoryBuilder.build
, when instantiating the client the request get stuck and we need to manually terminate the application execution.
After looking at https://github.com/splitio/ruby-client/blob/master/lib/engine/api/client.rb#L10
, I saw that we are instantiating Faraday
with FaradayMiddleware::Gzip
, which is a dependency defined in faraday_middleware
gem.
After digging my code I discovered that I already have installed faraday_middleware
in version 0.9.2
. The issue is that FaradayMiddleware::Gzip
is only available from version >= 0.10
https://github.com/lostisland/faraday_middleware/releases/tag/v0.10.0.
However, the currently .gemspec
is not specifying a minor version for faraday_middleware
, and if you already have a version installed, the gem will use that one, not matter which is the version of the installed gem. I will open a small PR to update .gemspec
to specify a minor version for faraday_middleware
as soon as possible ๐
Hi,
I would like to handle the case where the api key for split is invalid and we recover by assuming any feature's using split are disabled by default.
I was expecting to just rescue after creating the split factory, client, or calling block_until_ready
.
However, it seems the block_until_ready
method doesn't timeout when the api key is invalid.
Would you have an alternative suggestion such as a way to validate the API key first or should block_until_ready
timeout eventually?
Current behavior:
00:28:00 web.1 | Unexpected status code while fetching splits: 404. Check your API key and base URI
00:28:00 web.1 | [splitclient-rb] Unexpected exception in fetch_splits: #<RuntimeError: Split SDK failed to connect to backend to fetch split definitions> Split SDK failed to connect to backend to fetch split definitions
00:28:02 worker.1 | Unexpected status code while fetching splits: 404. Check your API key and base URI
00:28:02 worker.1 | [splitclient-rb] Unexpected exception in fetch_splits: #<RuntimeError: Split SDK failed to connect to backend to fetch split definitions> Split SDK failed to connect to backend to fetch split definitions
That repeats indefinitely.
Thanks!
Not sure where this should go, but we're running a ruby app that uses the split ruby sdk(7.0.0). The split-synchronizer(2.6.1) is running, attached to a redis instance. When the split-synchronizer first starts, everything is working fine, but after some time(maybe about a day or so), the split_manager will stop returning splits - ie, split_names is empty. If a split is changed in split.io though, that split starts coming back in split_names(and splits).
The split-synchronizer dashboard is fine, and looks like this:
The 400s in the error log seem to show up regardless of whether the issue is happening or not.
The health check is also fine:
At this point, the only thing that works is if split-synchronizer is restarted, then everything goes back to normal. Does anyone have any idea what might be the issue?
I tried to integrate split.io Ruby SDK with Rails, but found out the in-memory SDK in Rails console process never sync data with split.io website.
in config/initializers/split_client.rb
:
split_factory =
SplitIoClient::SplitFactory.new(ENV['SPLIT_IO_API_KEY'])
SPLIT_CLIENT = split_factory.client
Rails.configuration.split_factory = split_factory
begin
SPLIT_CLIENT.block_until_ready
rescue SplitIoClient::SDKBlockerTimeoutExpiredException => error
Rails.logger.error '=> Split.io SDK is not ready'
raise error
end
in config/puma.rb
:
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3030 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
workers ENV.fetch('WEB_CONCURRENCY') { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
preload_app!
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
before_fork { Rails.configuration.split_factory.stop! }
on_worker_boot { Rails.configuration.split_factory.resume! }
# experimental puma cluster mode flags
# https://github.com/puma/puma/blob/1840014e77c9c0b2e9e094135396c25dd3c1df52/5.0-Upgrade.md
wait_for_less_busy_worker 0.001
nakayoshi_fork
If I change the rule of a split in split.io dashboard, the SDK syncs configuration change with split.io website in Puma process, but in Rails console, it seems the SDK client never syncs and the rule in memory is stale.
I've created a dedicated repo to illustrate this phenomenon. The repo is https://github.com/crypt0leslie/poc-test-split-io
Procedures to reproduce are described in the README.md of this repo.
attributes do not get sent to split when running locally. looks like they don't get used:
https://github.com/splitio/ruby-client/blob/master/lib/splitclient-rb/clients/localhost_split_client.rb
While debugging an incident, we noticed that
is doing an early loop exit without delaying which causes too much CPU usage when the split key is invalid.I noticed that no matter what attributes I was passing into get_treatment
, my dashboard in Split.io logged the request but without attributes.
client.get_treatment("SOME_USER", "SOME_TEST", { random_attribute: "blah" })
Looks like attributes are completely ignore here: https://github.com/splitio/ruby-client/blob/master/lib/splitclient-rb/clients/localhost_split_client.rb#L44-L56
It appears CI is running against Ruby 2.5 https://github.com/splitio/ruby-client/blame/master/.github/workflows/ci.yml#L26 which is EOL as of 2021. https://www.ruby-lang.org/en/downloads/branches/
Congrats, this gem looks really nice and I'm really looking forward to using this it with the Split.io service.
While doing a technical review, I noticed that the gem has several namespace issues. These appear to be simple fixes but wanted your thoughts before doing a pull request.
Below are some reference articles on best practices on how to structure the gem lib directory. Having been bitten by these issues before, I consider these really important because file load conflicts are very hard to fix from the outside.
The directories lib/cache
, lib/engine
, and lib/exceptions
would need to be in lib/splitcient-rb/...
to avoid conflicts. Good news is that each file has the proper module namespace, so a simple git mv for each of these directories followed by changes to paths in sliptclient-rb.rb
should be sufficient.
The other issue I see is that lib/splitclient-rb_utilities.rb
defines a top level Utilities
constant. This file name is OK since it is prefixed with the gem name, however, that module name is very ambiguous. Suggest changing the contents to use the SplitIoClient::Utilities
namespace and making changes in the code to remove the ::
in places and everything should work fine.
What do you think? Is this something that you can fix or would you like a PR for it?
Again, thanks for the great work in the gem.
I'm using your service and the 7.3.4 gem version. I'm running into this error when updates come back:
Error during parsing a event: #<JSON::ParserError: unexpected token at 'data:
{"id":"xbWhZupEwC:0:0","timestamp":1711579820508,"clientId":"pri:MzU2Nzc3Mzc4NQ==","channel":"MjYyNDc3NDY0OQ==_NDAwMTc1NDgxNw==_splits","data":"{\"type\":\"SPLIT_UPDATE\",\"changeNumber\":1711579819987,\"pcn\":1711579723688,\"c\":2,\"d\":\"eJy8kk2L2zwcxL+KmbO8WLbjF93Cs8vT0DSBTdpSgimyLSdiZTnIMiUN/u5FSTabpqXQS2/S6P8y/o2PsIY3jazWh71Y8FaAgetOH9pu6EEgazA0eZTWSRr4ZRnkPqVC+FlEGz9LYtrENEuSPAaBPrc/LhfLZz+Lcr/uNLfC7/dKWpDXTVOluopb2WkwGgS/0VdC1GA0m+R5mKRJTNCfFJ/GYZYmNM4Iesvt0INh+t969ukJBC9SKVfVcNULglo0fFB2bQS3rdAWDJ0GQbXjeisWQ1sKA0ZTSidpntE8z1K3x/Zgm4KAq20HFhJUnW7kdjAnZz3YcTxptbzcN8e3q4MIhuflfL78uAZBy221E+Z/0w17MFfZllK7xZguHt8KznNexGEllKhsZ1zxTTJ3qXBrjSwH6/Rm0LXhshcG43Xepefzu9n6aT5bOStabLlruOD5tpNWKNnbD+eOR265W3rVwTagYQSCMKDRZAICSpM8Px2iKI7D10OEYhyLkWDPjb3BYu/R9/K7OGU+krvXprk+B2NBoHgp1E8f50ntOVvehoYR8c6eiPfw8FDAjfvHGfyCejqff33/9GV1T/ovwPwRi6N2A+byd3tmUAJjMf4IAAD//4H5OTc=\"}","encoding":"json"}'>
This is when running in local dev. I'm not sure if these issues are happening elsewhere.
Upgrading to the latest gem isn't much of an option for us. We're trying to use Split to help us migrate off of this old project.
Thanks!
We recently upgraded some components in our application and are running 7.0.3 of your gem.
We're using a redis-namespace
gem which has upgraded our redis
gem to version 4.2.2. I see you are also including the redis gem in your gem-spec: https://github.com/splitio/ruby-client/blob/master/splitclient-rb.gemspec#L58
We're now getting a deprecation warning on this line of code in your gem: https://github.com/splitio/ruby-client/blob/master/lib/splitclient-rb/cache/adapters/redis_adapter.rb#L38
I noticed in your test files that you're already appending the ?
so it won't be an issue there, but you'll need to make adjustment to use the ?
in your code before your gem can upgrade to redis
4.3.
The change is obviously very quick and you already have test coverage for the exists
method. We'd love to resolve the deprecation warning to clean up our log file output. Would you mind making the change or I'm happy to fork and submit a PR if you'd prefer I submit the change for consideration.
Let me know.
Hello!
We have a Split setup using the Ruby client in consumer mode, with Redis to communicate with the split synchronizer. The fix_latencies
fix found here has the effect of consuming a ton of Redis resources. This is run on each restart of the servers, and on each app server where we use the split gem. With a large number of app servers, and a shared Redis instance, the repeated scan
commands are causing Redis performance issues.
Could we have an option to disable the fix? It has already been run, and doesn't need to be re-run each restart.
Thanks!
Streaming events have been failing silently with JSON::ParserError: Empty input (after ) at line 1, column 1
when trying to parse a streaming event containing a payload missing a leading curly brace. The client did not automatically fallback to polling. The errors were only logged in debug mode and so we weren't alerted to the issue in our production logs. This led to large delays (>30min) from the time a flag definition was updated to the time our application would pick up the change. Only new deploys of the application would pick up new changes.
We are on v8.2.0 of the SDK.
This is happening here
Example payload missing leading curly brace:
'data:{"id":"6FMuBkchWr:0:0","timestamp":1710261542842, ... data":"{\"type\":\"SPLIT_UPDATE\", ...
I am receiving below error in my logger frequently:
Splitio: Error during connecting to streaming.split.io. Error: #<Socketry::TimeoutError: connection to 18.66.248.99:443 timed out>
Splitio: #<Socketry::TimeoutError: read timed out after 70 seconds>
Splitio: #<RuntimeError: eof exception>
Are these any concern?
This is just a lazy support question and I would be fine sending an email or discussing elsewhere. How much can one use the default MemoryAdapters::MapAdapter
with a typical Rails application that takes a "descent" amount of web traffic?
I am new to Ruby and to Split, although, the code that was generated on the Quickstart: SDK Setup has an issue. The code is below:
require 'splitclient-rb'
options = {
block_until_ready: 10
}
factory = SplitIoClient::SplitFactoryBuilder.build(API_KEY, options)
split_client = factory.client
treatment = split_client.get_treatment('CUSTOMER_ID', 'test')
if treatment == 'on'
puts 'I am on'
elsif treatment == 'off'
puts 'I am off'
else
puts 'Control'
end
Independently of the block_until_ready
value, I have increased it to 120, I always got ERROR -- : get_treatment: the SDK is not ready, the operation cannot be executed.
Solved it with split_client.block_until_ready
but then I remove the instruction and afterward, I did a while loop to check how much time it would take to establish the connection:
while 1 do
treatment = split_client.get_treatment('CUSTOMER_ID', 'test')
if treatment == 'on'
puts 'I am on'
elsif treatment == 'off'
puts 'I am off'
else
puts 'Control'
end
sleep(1)
end
And it would work after 1s, so I conclude that options
with the block_until_ready
is doing nothing.
Now I am not sure if it is a bug or if it is only the generated tutorial code that is wrong.
I am using splitclient-rb (7.2.2).
Rake 13.0.x introduces fixes in PR #326 which fix kwargs behavior which is currently broken when trying to develop locally in this project on newer Ruby versions.
I'm using the ruby client gem in one of our projects at Talkdesk and when running on JRuby an error is thrown due to a dependency using C extensions:
Just wondering if this is a known limitation and if there is value in being compatible with JRuby?
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory:
/usr/local/bundle/gems/digest-murmurhash-1.1.1/ext/digest/murmurhash
/opt/jruby/bin/jruby -r ./siteconf20180209-5-1h8ixdd.rb extconf.rb
creating Makefile
current directory:
/usr/local/bundle/gems/digest-murmurhash-1.1.1/ext/digest/murmurhash
make "DESTDIR=" clean
current directory:
/usr/local/bundle/gems/digest-murmurhash-1.1.1/ext/digest/murmurhash
make "DESTDIR="
make: *** No rule to make target '/opt/jruby/lib/ruby/include/ruby/ruby.h',
needed by 'neutral2.o'. Stop.
make failed, exit code 2
Gem files will remain installed in
/usr/local/bundle/gems/digest-murmurhash-1.1.1 for inspection.
Trying to move forward on bundling this gem and hitting issues. I noticed there is a twiddle wakka dep for the JSON gem to ~> 1.8
. Checking the released for the gem does show recent updates for that version.
https://rubygems.org/gems/json/versions
I can explore setting ~> 1.8
in my Rails v5 app's Gemfile, but is there a reason we are locked down to 1.8? Can the dep be open ended or >= 1.8
or something?
[redacted]
https://github.com/splitio/ruby-client/blame/master/Detailed-README.md#L372
The detailed documentation is a bit confusing. It mentions a memory
cache when using Redis. Why would a consumer use a memory
cache if it's already using Redis?
Similarly, why would a cache_ttl
exists if the consumer is only reading the cache? I would assume those option should live in the synchronizer
, no?
Can you tell if or when you will support faraday version 2.0 and above? This limitation is preventing us from evaluating Split's services.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.