splitclient-rb 4.5.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +45 -0
- data/CHANGES.txt +147 -0
- data/Detailed-README.md +571 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/NEWS +75 -0
- data/README.md +43 -0
- data/Rakefile +24 -0
- data/exe/splitio +96 -0
- data/ext/murmurhash/MurmurHash3.java +162 -0
- data/lib/murmurhash/base.rb +58 -0
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/murmurhash/murmurhash_mri.rb +3 -0
- data/lib/splitclient-rb.rb +90 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +133 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +44 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +165 -0
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +30 -0
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +29 -0
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +41 -0
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +78 -0
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +21 -0
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +129 -0
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +98 -0
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +22 -0
- data/lib/splitclient-rb/cache/repositories/repository.rb +23 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +82 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +106 -0
- data/lib/splitclient-rb/cache/routers/impression_router.rb +52 -0
- data/lib/splitclient-rb/cache/senders/events_sender.rb +47 -0
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +73 -0
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +67 -0
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +49 -0
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +48 -0
- data/lib/splitclient-rb/cache/stores/segment_store.rb +82 -0
- data/lib/splitclient-rb/cache/stores/split_store.rb +97 -0
- data/lib/splitclient-rb/clients/localhost_split_client.rb +92 -0
- data/lib/splitclient-rb/clients/split_client.rb +214 -0
- data/lib/splitclient-rb/engine/api/client.rb +74 -0
- data/lib/splitclient-rb/engine/api/events.rb +48 -0
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +55 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +42 -0
- data/lib/splitclient-rb/engine/api/metrics.rb +61 -0
- data/lib/splitclient-rb/engine/api/segments.rb +62 -0
- data/lib/splitclient-rb/engine/api/splits.rb +60 -0
- data/lib/splitclient-rb/engine/evaluator/splitter.rb +123 -0
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +46 -0
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +56 -0
- data/lib/splitclient-rb/engine/matchers/combiners.rb +9 -0
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +86 -0
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +21 -0
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +19 -0
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +30 -0
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +27 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +54 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +19 -0
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +53 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +53 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +24 -0
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +60 -0
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +23 -0
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +45 -0
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +128 -0
- data/lib/splitclient-rb/engine/metrics/metrics.rb +83 -0
- data/lib/splitclient-rb/engine/models/label.rb +8 -0
- data/lib/splitclient-rb/engine/models/split.rb +17 -0
- data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +210 -0
- data/lib/splitclient-rb/engine/parser/evaluator.rb +118 -0
- data/lib/splitclient-rb/engine/parser/partition.rb +35 -0
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +88 -0
- data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +4 -0
- data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +4 -0
- data/lib/splitclient-rb/localhost_split_factory.rb +13 -0
- data/lib/splitclient-rb/localhost_utils.rb +36 -0
- data/lib/splitclient-rb/managers/localhost_split_manager.rb +45 -0
- data/lib/splitclient-rb/managers/split_manager.rb +77 -0
- data/lib/splitclient-rb/split_config.rb +391 -0
- data/lib/splitclient-rb/split_factory.rb +35 -0
- data/lib/splitclient-rb/split_factory_builder.rb +16 -0
- data/lib/splitclient-rb/utilitites.rb +41 -0
- data/lib/splitclient-rb/version.rb +3 -0
- data/splitclient-rb.gemspec +50 -0
- data/splitio.yml.example +7 -0
- data/tasks/benchmark_get_treatment.rake +43 -0
- data/tasks/irb.rake +4 -0
- data/tasks/rspec.rake +3 -0
- metadata +321 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9073e7bb5019571936ef50983a19dfe65853dfd4
|
4
|
+
data.tar.gz: b0b44b977889c99b3dfc6dee34f658d2ee0129ec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 39c849665411940ce5ea4fbe212ef63fb71aa8d41e7dfef400675c19dd5c353bdc956fb7d5faeeeb6b0ca31ae28469ec8dd796126b30ef2aebc784a273dfcc8b
|
7
|
+
data.tar.gz: fd9adff75838c0b60e468e4155f224b0ae1dfc55ddc3d8e632cb7c256cd7b1cb9f0fdc9e56935719e86028087f1b09ce60e207b2746caa640819113d05523703
|
data/.gitignore
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/vendor/bundle
|
26
|
+
/lib/bundler/man/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
Gemfile.lock
|
31
|
+
.ruby-version
|
32
|
+
.ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
36
|
+
|
37
|
+
# Ignore Byebug command history file.
|
38
|
+
.byebug_history
|
39
|
+
|
40
|
+
# Ignore built extensions
|
41
|
+
lib/murmurhash/murmurhash.bundle
|
42
|
+
lib/murmurhash/murmurhash.so
|
43
|
+
|
44
|
+
ext/murmurhash/murmurhash.bundle
|
45
|
+
ext/murmurhash/murmurhash.so
|
data/CHANGES.txt
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
4.5.1 (Mar 23rd, 2018)
|
2
|
+
- Fix Forwardable load issue
|
3
|
+
- Fix native extension path issue
|
4
|
+
|
5
|
+
4.5.0 (Mar 2nd, 2018)
|
6
|
+
|
7
|
+
- Move MurmurHash3 implementation inside the gem
|
8
|
+
- Add native Java MurmurHash3 implementation -> now support JRuby
|
9
|
+
|
10
|
+
4.4.0 (Feb 5th, 2018)
|
11
|
+
- Add track API
|
12
|
+
|
13
|
+
4.3.3 (Feb 22th, 2018)
|
14
|
+
- Allow usage of Redis >= 3.2, not only ~> 3.2
|
15
|
+
|
16
|
+
4.3.2 (Dec 19th, 2017)
|
17
|
+
- Add DEFINITION_NOT_FOUND and rename NO_RULE_MATCHED labels
|
18
|
+
|
19
|
+
4.3.1 (Nov 10th, 2017)
|
20
|
+
- Do not throw exception when storing impressions on reids and it is not available. Returns CONTROL instead.
|
21
|
+
|
22
|
+
4.3.0 (Oct 13th, 2017)
|
23
|
+
- Add impression listener
|
24
|
+
- Add support for client shutdown (destroy())
|
25
|
+
- Add "time" to the routed impressions
|
26
|
+
- Add support to apply attribute matcher to the traffic type
|
27
|
+
- Add support for string matchers to match on matching keys
|
28
|
+
|
29
|
+
4.2.3 (August 4, 2017)
|
30
|
+
- Use ENV vars in producer
|
31
|
+
|
32
|
+
4.2.2 (July 28, 2017)
|
33
|
+
- Fix treatments array in SplitManager
|
34
|
+
|
35
|
+
4.2.1 (July 20, 2017)
|
36
|
+
- Coerce string to regexp for Regexp matcher
|
37
|
+
|
38
|
+
4.2.0 (July 18, 2017)
|
39
|
+
- Add new boolean/regexp matchers
|
40
|
+
- Add support for split dependency on other splits
|
41
|
+
- Pass bucketing_key to `match?` method
|
42
|
+
- Fix IP address fetching
|
43
|
+
- Remove unneeded dependencies (faraday_middleware, faraday-http-cache)
|
44
|
+
|
45
|
+
4.1.0 (April 16, 2017)
|
46
|
+
- Add new string/set matchers
|
47
|
+
- Use Rails logger if available. Now we do not pollute STDOUT by default
|
48
|
+
|
49
|
+
4.0.0
|
50
|
+
- Add support for murmur3 algo
|
51
|
+
- Optimize memory usage
|
52
|
+
|
53
|
+
3.3.0
|
54
|
+
- Add support for traffic allocation
|
55
|
+
|
56
|
+
3.2.4
|
57
|
+
- Fix Faraday compability issue (now compatible with Faraday 0.8.9)
|
58
|
+
- Provide an interface to run SplitAdapter(start and resume), can be used to resurrect threads in Unicorn and Passenger servers
|
59
|
+
- Allow passing non-string values to get_treatment/get_treatments
|
60
|
+
- Better logging when returning CONTROL and label:Exception as well as when restarting threads
|
61
|
+
- Add exception logging when failed to clear impressions keys or fetch impressions keys
|
62
|
+
- Fix Redis naming issues (key_name -> keyName)
|
63
|
+
- Fix negation matcher. Negation had not effect and was ignored.
|
64
|
+
|
65
|
+
3.2.3
|
66
|
+
- Fix Redis namespace issue to align with the spec
|
67
|
+
- Allocate less memory by not creating Split model to check if Split is archived
|
68
|
+
|
69
|
+
3.2.2
|
70
|
+
- Fix issue when segment_store was never invoked
|
71
|
+
|
72
|
+
3.2.0
|
73
|
+
- Add impression labeling
|
74
|
+
|
75
|
+
3.1.3
|
76
|
+
- Refactor SplitFactory - split it into separate mangers and client classes
|
77
|
+
- Refactor Utilities to comply style guide
|
78
|
+
- Allow to store block until ready flag in Redis
|
79
|
+
- rescue exception when posting impressions threads failed to prevent it to die
|
80
|
+
|
81
|
+
3.1.2
|
82
|
+
- Fix issue with complex key where get_treatment and get_treatments return different values.
|
83
|
+
|
84
|
+
3.1.1
|
85
|
+
- Fix variable not found when posting impression
|
86
|
+
- Fix infinite loop when posting impression if there is a network glitch
|
87
|
+
|
88
|
+
3.1.0
|
89
|
+
- Add RedisAdapter
|
90
|
+
- adds manager.split_names()
|
91
|
+
- add impressions_queue_size to prevent memory leak when Threads pauses due to 'smart' fork.
|
92
|
+
- do not report latencies for get_treatment is array is all zeros
|
93
|
+
- Fix deduplication problem when posting impressions
|
94
|
+
- Change in how factory is construct.
|
95
|
+
- Detach implementation for local factory and regular one.
|
96
|
+
|
97
|
+
3.0.3
|
98
|
+
|
99
|
+
- Fix nil ref in manager
|
100
|
+
|
101
|
+
3.0.2
|
102
|
+
|
103
|
+
- add ability to provide different bucketing/matching keys
|
104
|
+
|
105
|
+
3.0.1
|
106
|
+
|
107
|
+
- fix segments not deleting from the cache
|
108
|
+
|
109
|
+
3.0.0
|
110
|
+
|
111
|
+
- add new caching interface
|
112
|
+
- add replaceable adapters to store cache in
|
113
|
+
- add first cache adapter: MemoryAdapter
|
114
|
+
- refactoring
|
115
|
+
|
116
|
+
2.0.1
|
117
|
+
|
118
|
+
- Supress warnings cause by Net::HTTP when it already exists.
|
119
|
+
|
120
|
+
2.0.0
|
121
|
+
|
122
|
+
- Add Factory for creation of Client and Manager interface.
|
123
|
+
|
124
|
+
1.0.4
|
125
|
+
|
126
|
+
- added support for AND combiner on conditions
|
127
|
+
- added events_uri as config param which defines the metrics post url
|
128
|
+
- updated metrics post default endpoint to be https://events.split.io/api/
|
129
|
+
|
130
|
+
1.0.3
|
131
|
+
- fixed refresh rate intervals issue
|
132
|
+
- fixed datetime bug for split definitions created directly from api
|
133
|
+
|
134
|
+
1.0.2
|
135
|
+
- created between_matcher, equal_to_matcher, greater_than_or_equal_to_matcher, less_than_or_equal_to_matcher to support attributes
|
136
|
+
- refactored whitelist_matcher to support attributes
|
137
|
+
- tweaked to drop analytics data if the POST get an error response
|
138
|
+
- added condition to return CONTROL on the deleted features
|
139
|
+
|
140
|
+
1.0.1
|
141
|
+
|
142
|
+
- .splits to .split for local env
|
143
|
+
- isTreatment was removed from the API.
|
144
|
+
|
145
|
+
1.0.0
|
146
|
+
|
147
|
+
- Support multivariate treatment
|
data/Detailed-README.md
ADDED
@@ -0,0 +1,571 @@
|
|
1
|
+
# Split Ruby SDK
|
2
|
+
|
3
|
+
Ruby SDK for Split software, provided as a gem that can be installed to your Ruby application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
---
|
7
|
+
|
8
|
+
- Once the gem is published you can install it with the following steps:
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'splitclient-rb'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle install
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install splitclient-rb
|
23
|
+
|
24
|
+
- You can also use the most recent version from github:
|
25
|
+
|
26
|
+
Add these lines to you application's `Gemfile`:
|
27
|
+
```ruby
|
28
|
+
gem 'splitclient-rb', git: 'https://github.com/splitio/ruby-client.git',
|
29
|
+
```
|
30
|
+
You can also use any specific branch if necessary:
|
31
|
+
```ruby
|
32
|
+
gem 'splitclient-rb', git: 'https://github.com/splitio/ruby-client.git', branch: 'development'
|
33
|
+
```
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle install
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
### Quick Setup
|
41
|
+
---
|
42
|
+
|
43
|
+
Within your application you need the following:
|
44
|
+
|
45
|
+
Require the Split client:
|
46
|
+
```ruby
|
47
|
+
require 'splitclient-rb'
|
48
|
+
```
|
49
|
+
|
50
|
+
Create a new split client instance with your API key:
|
51
|
+
```ruby
|
52
|
+
factory = SplitIoClient::SplitFactoryBuilder.build('YOUR_API_KEY').client
|
53
|
+
split_client = factory.client
|
54
|
+
```
|
55
|
+
|
56
|
+
For advance use cases you can also obtain a `manager` instance from the factory.
|
57
|
+
```ruby
|
58
|
+
manager = factory.manager
|
59
|
+
```
|
60
|
+
|
61
|
+
#### Localhost mode
|
62
|
+
|
63
|
+
You can run SDK in so called "localhost" mode. In this mode SDK won't hit Split API and return treatments based on ".split" file on your local machine. The format of this file is two columns separated by whitespace. The left column is the Split name, the right column is the treatment name. Here is a sample file:
|
64
|
+
|
65
|
+
```
|
66
|
+
# this is a comment
|
67
|
+
|
68
|
+
# split_client.get_treatment('foo', 'reporting_v2') => 'on'
|
69
|
+
|
70
|
+
reporting_v2 on
|
71
|
+
double_writes_to_cassandra off
|
72
|
+
new-navigation v3
|
73
|
+
|
74
|
+
```
|
75
|
+
|
76
|
+
To use SDK in the localhost mode you should pass `localhost` as an API key like this:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
factory = SplitIoClient::SplitFactoryBuilder.build('localhost', path: '/where/to-look-for/<file_name>')
|
80
|
+
split_client = factory.client
|
81
|
+
```
|
82
|
+
|
83
|
+
By default SDK will look in your home directory (i.e. `~`) for a `.split` file, but you can specify a different
|
84
|
+
file name (full path) to look for the file (note: you must provide absolute path):
|
85
|
+
|
86
|
+
When in localhost mode you can make use of the SDK ability to automatically refresh splits from file, to do that just specify reload rate in seconds like this:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
factory = SplitIoClient::SplitFactoryBuilder.build('localhost', path: '/where/to-look-for/<file_name>', reload_rate: 3)
|
90
|
+
```
|
91
|
+
|
92
|
+
### Ruby on Rails
|
93
|
+
---
|
94
|
+
|
95
|
+
Create an initializer: `config/initializers/splitclient.rb` and then initialize the split client:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
Rails.configuration.split_client = SplitIoClient::SplitFactoryBuilder.build('YOUR_API_KEY').client
|
99
|
+
```
|
100
|
+
In your controllers, access the client using:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Rails.application.config.split_client
|
104
|
+
```
|
105
|
+
|
106
|
+
### Configuration
|
107
|
+
---
|
108
|
+
|
109
|
+
Split client's default configuration should be sufficient for most scenarios. However you can also provide custom configuration when initializing the client using an optional hash of options.
|
110
|
+
|
111
|
+
The following values can be customized:
|
112
|
+
|
113
|
+
**base_uri** : URI for the api endpoints
|
114
|
+
|
115
|
+
*defualt value* = `https://sdk.split.io/api/`
|
116
|
+
|
117
|
+
**connection_timeout** : timeout for network connections in seconds
|
118
|
+
|
119
|
+
*default value* = `5`
|
120
|
+
|
121
|
+
**read_timeout** : timeout for requests in seconds
|
122
|
+
|
123
|
+
*default value* = `5`
|
124
|
+
|
125
|
+
**features_refresh_rate** : The SDK polls Split servers for changes to feature roll-out plans. This parameter controls this polling period in seconds
|
126
|
+
split_client.get_treatment('user_id','feature_name', attr: 'val')
|
127
|
+
*default value* = `30`
|
128
|
+
|
129
|
+
**segments_refresh_rate** : The SDK polls Split servers for changes to segment definitions. This parameter controls this polling period in seconds
|
130
|
+
|
131
|
+
*default value* = `60`
|
132
|
+
|
133
|
+
**metrics_refresh_rate** : The SDK sends diagnostic metrics to Split servers. This parameters controls this metric flush period in seconds
|
134
|
+
|
135
|
+
*default value* = `60`
|
136
|
+
|
137
|
+
**impressions_refresh_rate** : The SDK sends information on who got what treatment at what time back to Split servers to power analytics. This parameter controls how often this data is sent to Split servers in seconds
|
138
|
+
|
139
|
+
**impressions_queue_size** : The size of the impressions queue in case of `cache_adapter == :memory` and the size impressions batch to be fetched from Redis in case of `cache_adapter == :redis`. Use `-1` to disable impressions.
|
140
|
+
|
141
|
+
*default value* = `60`
|
142
|
+
|
143
|
+
**debug_enabled** : Enables extra logging
|
144
|
+
|
145
|
+
*default value* = `false`
|
146
|
+
|
147
|
+
**transport_debug_enabled** : Enables extra transport logging
|
148
|
+
|
149
|
+
*default value* = `false`
|
150
|
+
|
151
|
+
**logger** : default logger for messages and errors
|
152
|
+
|
153
|
+
*default value* = `Logger.new($stdout)`
|
154
|
+
|
155
|
+
**ready** : The SDK will block your app for provided amount of seconds until it's ready. If timeout expires `SplitIoClient::SDKBlockerTimeoutExpiredException` will be thrown. If `0` provided, then SDK would run in non-blocking mode
|
156
|
+
|
157
|
+
*default value* = `0`
|
158
|
+
|
159
|
+
**labels_enabled** : Enables sending labels along with sensitive information
|
160
|
+
|
161
|
+
*default value* = `true`
|
162
|
+
|
163
|
+
**mode** : See [SDK modes section](#sdk-modes).
|
164
|
+
|
165
|
+
*default value* = `:standalone`
|
166
|
+
|
167
|
+
#### Cache adapter
|
168
|
+
|
169
|
+
The SDK needs some container to store data, i.e. splits/segments/impressions. By default it will store everything in the application's memory, but you can also use Redis.
|
170
|
+
|
171
|
+
To use Redis, you have to include `redis-rb` in your app's Gemfile.
|
172
|
+
|
173
|
+
**cache_adapter** : Supported options: `:memory`, `:redis`
|
174
|
+
|
175
|
+
*default value* = `memory`
|
176
|
+
|
177
|
+
**language** : SDK runner language (used in metrics/impressions Redis namespace)
|
178
|
+
|
179
|
+
*default value* = `'ruby'`
|
180
|
+
|
181
|
+
**version** : SDK runner version (used in metrics/impressions Redis namespace)
|
182
|
+
|
183
|
+
*default value* = `current version of Ruby SDK`
|
184
|
+
|
185
|
+
**machine_ip** : SDK runner machine ip (used in metrics/impressions Redis namespace)
|
186
|
+
|
187
|
+
*default value* = `current host's ip`
|
188
|
+
|
189
|
+
**machine_name** : SDK runner machine name (used in metrics/impressions Redis namespace)
|
190
|
+
|
191
|
+
*default value* = `current hostname`
|
192
|
+
|
193
|
+
**redis_url** : Redis URL or hash with configuration for SDK to connect to.
|
194
|
+
|
195
|
+
*default value* = `'redis://127.0.0.1:6379/0'`
|
196
|
+
|
197
|
+
You can also use Sentinel like this:
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
SENTINELS = [{host: '127.0.0.1', port: 26380},
|
201
|
+
{host: '127.0.0.1', port: 26381}]
|
202
|
+
|
203
|
+
redis_connection = { url: 'redis://mymaster', sentinels: SENTINELS, role: :master }
|
204
|
+
|
205
|
+
options = {
|
206
|
+
# Other options here
|
207
|
+
redis_url: redis_connection
|
208
|
+
}
|
209
|
+
```
|
210
|
+
|
211
|
+
Example using Redis
|
212
|
+
```ruby
|
213
|
+
options = {
|
214
|
+
connection_timeout: 10,
|
215
|
+
read_timeout: 5,
|
216
|
+
features_refresh_rate: 120,
|
217
|
+
segments_refresh_rate: 120,
|
218
|
+
metrics_refresh_rate: 360,
|
219
|
+
impressions_refresh_rate: 360,
|
220
|
+
logger: Logger.new('logfile.log'),
|
221
|
+
cache_adapter: :redis,
|
222
|
+
mode: :standalone,
|
223
|
+
redis_url: 'redis://127.0.0.1:6379/0'
|
224
|
+
}
|
225
|
+
begin
|
226
|
+
split_client = SplitIoClient::SplitFactoryBuilder.build('YOUR_API_KEY', options).client
|
227
|
+
rescue SplitIoClient::SDKBlockerTimeoutExpiredException
|
228
|
+
# Some arbitrary actions
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
#### Unicorn
|
233
|
+
|
234
|
+
When using Unicorn without Redis (i.e. in memory mode) it's highly recommended to include the startup code above inside Unicorn's `after_fork` hook:
|
235
|
+
|
236
|
+
*unicorn.rb*
|
237
|
+
```ruby
|
238
|
+
# Unicorn configuration
|
239
|
+
after_fork do
|
240
|
+
options = {
|
241
|
+
connection_timeout: 10,
|
242
|
+
read_timeout: 5,
|
243
|
+
features_refresh_rate: 120,
|
244
|
+
segments_refresh_rate: 120,
|
245
|
+
metrics_refresh_rate: 360,
|
246
|
+
impressions_refresh_rate: 360,
|
247
|
+
logger: Logger.new('logfile.log'),
|
248
|
+
cache_adapter: :redis,
|
249
|
+
mode: :standalone,
|
250
|
+
redis_url: 'redis://127.0.0.1:6379/0'
|
251
|
+
}
|
252
|
+
begin
|
253
|
+
split_client = SplitIoClient::SplitFactoryBuilder.build('YOUR_API_KEY', options).client
|
254
|
+
rescue SplitIoClient::SDKBlockerTimeoutExpiredException
|
255
|
+
# Some arbitrary actions
|
256
|
+
end
|
257
|
+
end
|
258
|
+
```
|
259
|
+
|
260
|
+
When initializing the SDK this way, SDK will only run HTTP requests from workers, not master process.
|
261
|
+
|
262
|
+
#### IMPORTANT
|
263
|
+
|
264
|
+
For now, SDK does not support both `producer` mode and `ready`. You must either run SDK in `standalone` mode, or do not use `ready` option.
|
265
|
+
|
266
|
+
This begin-rescue-end block is optional, you might want to use it to catch timeout expired exception and apply some logic.
|
267
|
+
|
268
|
+
### Execution
|
269
|
+
---
|
270
|
+
|
271
|
+
In your application code you just need to call the `get_treatment` method with the required parameters for key and feature name:
|
272
|
+
```ruby
|
273
|
+
split_client.get_treatment('user_id','feature_name', attr: 'val')
|
274
|
+
```
|
275
|
+
|
276
|
+
For example
|
277
|
+
```ruby
|
278
|
+
if split_client.get_treatment('employee_user_01','view_main_list', age: 35)
|
279
|
+
my_app.display_main_list
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
Also, you can use different keys for actually getting treatment and sending impressions to the server:
|
284
|
+
```ruby
|
285
|
+
split_client.get_treatment(
|
286
|
+
{ matching_key: 'user_id', bucketing_key: 'private_user_id' },
|
287
|
+
'feature_name',
|
288
|
+
attr: 'val'
|
289
|
+
)
|
290
|
+
```
|
291
|
+
When it might be useful? Say, you have a user browsing your website and not signed up yet. You assign some internal id to that user (i.e. bucketing_key) and after user signs up you assign him a matching_key.
|
292
|
+
By doing this you can provide both anonymous and signed up user with the same treatment.
|
293
|
+
|
294
|
+
`bucketing_key` may be `nil` in that case `matching_key` would be used as a key, so calling
|
295
|
+
```ruby
|
296
|
+
split_client.get_treatment(
|
297
|
+
{ matching_key: 'user_id' },
|
298
|
+
'feature_name',
|
299
|
+
attr: 'val'
|
300
|
+
)
|
301
|
+
```
|
302
|
+
Is exactly the same as calling
|
303
|
+
```ruby
|
304
|
+
split_client.get_treatment('user_id' ,'feature_name', attr: 'val')
|
305
|
+
```
|
306
|
+
`bucketing_key` must not be nil
|
307
|
+
|
308
|
+
Also you can use the split manager:
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
split_manager = SplitIoClient::SplitFactoryBuilder.build('your_api_key', options).manager
|
312
|
+
```
|
313
|
+
|
314
|
+
With the manager you can get a list of your splits by doing:
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
manager.splits
|
318
|
+
```
|
319
|
+
|
320
|
+
And you should get something like this:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
[
|
324
|
+
{
|
325
|
+
name: 'some_feature',
|
326
|
+
traffic_type_name: nil,
|
327
|
+
killed: false,
|
328
|
+
treatments: nil,
|
329
|
+
change_number: 1469134003507
|
330
|
+
},
|
331
|
+
{
|
332
|
+
name: 'another_feature',
|
333
|
+
traffic_type_name: nil,
|
334
|
+
killed: false,
|
335
|
+
treatments: nil,
|
336
|
+
change_number: 1469134003414
|
337
|
+
},
|
338
|
+
{
|
339
|
+
name: 'even_more_features',
|
340
|
+
traffic_type_name: nil,
|
341
|
+
killed: false,
|
342
|
+
treatments: nil,
|
343
|
+
change_number: 1469133991063
|
344
|
+
},
|
345
|
+
{
|
346
|
+
name: 'yet_another_feature',
|
347
|
+
traffic_type_name: nil,
|
348
|
+
killed: false,
|
349
|
+
treatments: nil,
|
350
|
+
change_number: 1469133757521
|
351
|
+
}
|
352
|
+
]
|
353
|
+
```
|
354
|
+
|
355
|
+
### Logging
|
356
|
+
|
357
|
+
Ruby SDK makes use of Ruby stdlib's `Logger` class to log errors/events, default option is: `Logger.new($stdout)`.
|
358
|
+
|
359
|
+
You can configure the following options in the config file:
|
360
|
+
|
361
|
+
```
|
362
|
+
logger: Logger.new('logfile.log'), # you can specify your own Logger class instance here
|
363
|
+
debug_enabled: true, # used for more verbose logging, including more debug information (false is the default)
|
364
|
+
transport_debug_enabled: true # used for log transport data (mostly http requests, false is the default)
|
365
|
+
```
|
366
|
+
|
367
|
+
### Impression Listener
|
368
|
+
|
369
|
+
In order to capture every single impression in your app SDK provides option called Impression Listener. It works pretty straightforward: you define a class which must have instance method called `log`, which must receive 1 argument `impression`. Let's say you have the following impression listener class:
|
370
|
+
|
371
|
+
```ruby
|
372
|
+
class MyImpressionListener
|
373
|
+
def log(impression)
|
374
|
+
Logger.new($stdout).info(impression)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
Nothing fancy here, it just takes impression and logs it to the stdout. Now, to actually use this class you'll need to specify it in your config (i.e. initializer) like this:
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
{
|
383
|
+
# other options
|
384
|
+
impression_listener: MyImpressionListener.new # do remember to initialize your class here
|
385
|
+
}
|
386
|
+
```
|
387
|
+
|
388
|
+
### SDK Modes
|
389
|
+
|
390
|
+
By default SDK would run alongside with your application and will be run in `standalone` mode, which includes two modes:
|
391
|
+
- `producer` - storing information from the Splits API in the chosen cache
|
392
|
+
- `consumer` - retrieving data from the cache and providing `get_treatment` interface
|
393
|
+
|
394
|
+
As you might think, you can choose between these 3 modes by providing `mode` option in the config.
|
395
|
+
|
396
|
+
#### Producer mode
|
397
|
+
|
398
|
+
If you have, say, one Redis cache which is used by several Split SDKs at once, e.g.: Python and Ruby, you want to have only one of them to write data to Redis, so it would remain consistent. That's why we have producer mode.
|
399
|
+
|
400
|
+
SDK can be ran in `producer` mode both in the scope of the application (e.g. as a part of the Rails app), and as a separate process. Let's see what steps are needed to run it as a separate process:
|
401
|
+
|
402
|
+
- You need to create a config file with .yml extension. All options specified in the above example section are valid, but you should write them in the YAML format, like this:
|
403
|
+
|
404
|
+
```yaml
|
405
|
+
---
|
406
|
+
:api_key: 'SECRET_API_KEY'
|
407
|
+
:connection_timeout: 10
|
408
|
+
:read_timeout: 5
|
409
|
+
:features_refresh_rate: 120
|
410
|
+
:segments_refresh_rate: 120
|
411
|
+
:metrics_refresh_rate: 360
|
412
|
+
:impressions_refresh_rate: 360
|
413
|
+
:cache_adapter: :redis
|
414
|
+
:mode: :producer
|
415
|
+
:redis_url: 'redis://127.0.0.1:6379/0'
|
416
|
+
```
|
417
|
+
|
418
|
+
|
419
|
+
- Install binstubs
|
420
|
+
```ruby
|
421
|
+
bundle binstubs splitclient-rb
|
422
|
+
```
|
423
|
+
|
424
|
+
- Run the executable provided by the SDK:
|
425
|
+
```ruby
|
426
|
+
bundle exec bin/splitio -c ~/path/to/config/file.yml
|
427
|
+
```
|
428
|
+
|
429
|
+
Also, you can pass options directly to the cli command, like this:
|
430
|
+
```
|
431
|
+
bundle exec bin/splitio -c ~/path/to/config/file.yml --debug
|
432
|
+
```
|
433
|
+
|
434
|
+
Note: options passed through cli have higher priority than those specified in the configuration file. To see the full list of supported options you can run:
|
435
|
+
```
|
436
|
+
bundle exec bin/splitio -h
|
437
|
+
```
|
438
|
+
## Server support
|
439
|
+
|
440
|
+
Currently SDK supports:
|
441
|
+
- Thin
|
442
|
+
- Puma
|
443
|
+
- Passenger
|
444
|
+
- Unicorn
|
445
|
+
|
446
|
+
Other servers should work fine as well, but haven't been tested.
|
447
|
+
|
448
|
+
### Unicorn and Puma in cluster mode (only for "memory mode")
|
449
|
+
|
450
|
+
During the start of your application SDK spawns multiple threads, each thread has an infinite loop inside which is used to fetch splits/segments or send impressions/metrics.
|
451
|
+
Several servers like Unicorn and Puma in cluster mode (i.e. with `workers` > 0) spawn multiple child processes, but when child process is spawn it does not recreate threads, which existed in the parent process, that's why if you use Unicorn or Puma in cluster mode you need to make two small extra steps.
|
452
|
+
|
453
|
+
For both servers you will need to have the following line in your `config/initializers/splitclient.rb`:
|
454
|
+
|
455
|
+
```ruby
|
456
|
+
Rails.configuration.split_factory = factory
|
457
|
+
```
|
458
|
+
|
459
|
+
#### Unicorn
|
460
|
+
|
461
|
+
If you're using Unicorn you'll need to include this line in your Unicorn config (probably `config/unicorn.rb`):
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
after_fork do |server, worker|
|
465
|
+
Rails.configuration.split_factory.resume! if worker.nr > 0
|
466
|
+
end
|
467
|
+
```
|
468
|
+
|
469
|
+
By doing that SDK will recreate threads for each new worker, besides master.
|
470
|
+
|
471
|
+
#### Puma
|
472
|
+
|
473
|
+
For those who use Puma in cluster mode add this to your Puma config (probably `config/puma.rb`):
|
474
|
+
|
475
|
+
```ruby
|
476
|
+
on_worker_boot do |worker_number|
|
477
|
+
Rails.configuration.split_factory.resume! if worker_number.nr > 0
|
478
|
+
end
|
479
|
+
```
|
480
|
+
|
481
|
+
By doing that SDK will recreate threads for each new worker, besides master.
|
482
|
+
|
483
|
+
## Proxy support
|
484
|
+
|
485
|
+
SDK respects http_proxy environment variable, all you need to do to use proxy is assign your proxy address to that variable in the format:
|
486
|
+
|
487
|
+
```
|
488
|
+
http_proxy=http://username:password@hostname:port
|
489
|
+
```
|
490
|
+
|
491
|
+
## Framework support
|
492
|
+
|
493
|
+
Currently SDK supports:
|
494
|
+
- Rails
|
495
|
+
|
496
|
+
SDK should work with other frameworks too, but for now it has been tested only with Rails
|
497
|
+
|
498
|
+
## Development
|
499
|
+
|
500
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
501
|
+
|
502
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
503
|
+
|
504
|
+
## Coverage
|
505
|
+
|
506
|
+
The gem uses rspec for unit testing. Under the default `/spec` folder you will find the files for the unit tests and the specs helper file ( spec_helper.rb ). If a new spec file with new unit tests is required you just simply need to create it under the spec folder and all its test will be executed on the next rspec execution.
|
507
|
+
|
508
|
+
To run the suite of unit tests a rake task is provided.
|
509
|
+
|
510
|
+
Make sure redis is running in localhost at redis://127.0.0.1:6379/0 and then just run:
|
511
|
+
```bash
|
512
|
+
SPLITCLIENT_ENV=test bundle exec rspec spec
|
513
|
+
```
|
514
|
+
|
515
|
+
Also, simplecov is used for coverage reporting. After the execution of the rake task it will create the `/coverage` folder with coverage reports in pretty HTML format.
|
516
|
+
Right now, the code coverage of the gem is at about 95%.
|
517
|
+
|
518
|
+
## Release
|
519
|
+
|
520
|
+
```bash
|
521
|
+
gem build splitclient-rb.gemspec
|
522
|
+
```
|
523
|
+
|
524
|
+
This will generate a file gemspec with the right version, then:
|
525
|
+
|
526
|
+
```bash
|
527
|
+
gem push splitclient-rb-<VERSION>.gem
|
528
|
+
```
|
529
|
+
|
530
|
+
## Benchmarking
|
531
|
+
|
532
|
+
To benchmark hashing algorithms (currently we're using MurmurHash) you'll need to run:
|
533
|
+
|
534
|
+
```bash
|
535
|
+
bundle exec rake benchmark_hashing_algorithm
|
536
|
+
```
|
537
|
+
|
538
|
+
## Contributing
|
539
|
+
|
540
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/splitio/ruby-client.
|
541
|
+
|
542
|
+
## Gem version publish
|
543
|
+
|
544
|
+
To build a new version of the gem, after you have finished the desired changes, documented the CHANGES.txt and the NEWS, as well as named it properly in the version.rb. This steps assume that all of your new cool features and fixes have been merged into development, and into master branches of the ruby-client repo. Once that is ready to go, you will have to run the build command to obtain a .gem file:
|
545
|
+
|
546
|
+
```bash
|
547
|
+
gem build splitclient-rb.gemspec
|
548
|
+
```
|
549
|
+
|
550
|
+
That will generate a splitclient-rb-x.x.x.gem file, with the corresponding version information on it.
|
551
|
+
To publish this new version of the gem at rubygems.org you must run the following command:
|
552
|
+
|
553
|
+
```bash
|
554
|
+
gem push splitclient-rb-x.x.x.gem
|
555
|
+
```
|
556
|
+
|
557
|
+
A valid rubygems username and password will be required.
|
558
|
+
|
559
|
+
After this action, the new splitclient-rb-x.x.x version is available for its use from any ruby app.
|
560
|
+
|
561
|
+
So for instance in a rails app Gemfile, you could add the:
|
562
|
+
|
563
|
+
```ruby
|
564
|
+
gem 'splitclient-rb', '~> x.x.x'
|
565
|
+
```
|
566
|
+
|
567
|
+
line to have the latest version of the gem ready to be used.
|
568
|
+
|
569
|
+
## License
|
570
|
+
|
571
|
+
The gem is available as open source under the terms of the [Apache License](http://www.apache.org/licenses/).
|