splitclient-rb 4.5.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +45 -0
  3. data/CHANGES.txt +147 -0
  4. data/Detailed-README.md +571 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +13 -0
  7. data/NEWS +75 -0
  8. data/README.md +43 -0
  9. data/Rakefile +24 -0
  10. data/exe/splitio +96 -0
  11. data/ext/murmurhash/MurmurHash3.java +162 -0
  12. data/lib/murmurhash/base.rb +58 -0
  13. data/lib/murmurhash/murmurhash.jar +0 -0
  14. data/lib/murmurhash/murmurhash_mri.rb +3 -0
  15. data/lib/splitclient-rb.rb +90 -0
  16. data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
  17. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +133 -0
  18. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +44 -0
  19. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +165 -0
  20. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +30 -0
  21. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +29 -0
  22. data/lib/splitclient-rb/cache/repositories/events_repository.rb +41 -0
  23. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +49 -0
  24. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +78 -0
  25. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +21 -0
  26. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +129 -0
  27. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +98 -0
  28. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +22 -0
  29. data/lib/splitclient-rb/cache/repositories/repository.rb +23 -0
  30. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +82 -0
  31. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +106 -0
  32. data/lib/splitclient-rb/cache/routers/impression_router.rb +52 -0
  33. data/lib/splitclient-rb/cache/senders/events_sender.rb +47 -0
  34. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +73 -0
  35. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +67 -0
  36. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +49 -0
  37. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +48 -0
  38. data/lib/splitclient-rb/cache/stores/segment_store.rb +82 -0
  39. data/lib/splitclient-rb/cache/stores/split_store.rb +97 -0
  40. data/lib/splitclient-rb/clients/localhost_split_client.rb +92 -0
  41. data/lib/splitclient-rb/clients/split_client.rb +214 -0
  42. data/lib/splitclient-rb/engine/api/client.rb +74 -0
  43. data/lib/splitclient-rb/engine/api/events.rb +48 -0
  44. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +55 -0
  45. data/lib/splitclient-rb/engine/api/impressions.rb +42 -0
  46. data/lib/splitclient-rb/engine/api/metrics.rb +61 -0
  47. data/lib/splitclient-rb/engine/api/segments.rb +62 -0
  48. data/lib/splitclient-rb/engine/api/splits.rb +60 -0
  49. data/lib/splitclient-rb/engine/evaluator/splitter.rb +123 -0
  50. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +46 -0
  51. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +56 -0
  52. data/lib/splitclient-rb/engine/matchers/combiners.rb +9 -0
  53. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +86 -0
  54. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +21 -0
  55. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +19 -0
  56. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +30 -0
  57. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +20 -0
  58. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +26 -0
  59. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +27 -0
  60. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +54 -0
  61. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +19 -0
  62. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +53 -0
  63. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +53 -0
  64. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +24 -0
  65. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +60 -0
  66. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +23 -0
  67. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +20 -0
  68. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +26 -0
  69. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +45 -0
  70. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
  71. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +128 -0
  72. data/lib/splitclient-rb/engine/metrics/metrics.rb +83 -0
  73. data/lib/splitclient-rb/engine/models/label.rb +8 -0
  74. data/lib/splitclient-rb/engine/models/split.rb +17 -0
  75. data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
  76. data/lib/splitclient-rb/engine/parser/condition.rb +210 -0
  77. data/lib/splitclient-rb/engine/parser/evaluator.rb +118 -0
  78. data/lib/splitclient-rb/engine/parser/partition.rb +35 -0
  79. data/lib/splitclient-rb/engine/parser/split_adapter.rb +88 -0
  80. data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +4 -0
  81. data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +4 -0
  82. data/lib/splitclient-rb/localhost_split_factory.rb +13 -0
  83. data/lib/splitclient-rb/localhost_utils.rb +36 -0
  84. data/lib/splitclient-rb/managers/localhost_split_manager.rb +45 -0
  85. data/lib/splitclient-rb/managers/split_manager.rb +77 -0
  86. data/lib/splitclient-rb/split_config.rb +391 -0
  87. data/lib/splitclient-rb/split_factory.rb +35 -0
  88. data/lib/splitclient-rb/split_factory_builder.rb +16 -0
  89. data/lib/splitclient-rb/utilitites.rb +41 -0
  90. data/lib/splitclient-rb/version.rb +3 -0
  91. data/splitclient-rb.gemspec +50 -0
  92. data/splitio.yml.example +7 -0
  93. data/tasks/benchmark_get_treatment.rake +43 -0
  94. data/tasks/irb.rake +4 -0
  95. data/tasks/rspec.rake +3 -0
  96. metadata +321 -0
@@ -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
@@ -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
@@ -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
@@ -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/).