splitclient-rb 1.0.2.wip → 8.11.1.pre.rc1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/pull_request_template.md +9 -0
  4. data/.github/workflows/ci.yml +90 -0
  5. data/.github/workflows/update-license-year.yml +45 -0
  6. data/.gitignore +20 -0
  7. data/.rubocop.yml +76 -0
  8. data/.simplecov +1 -0
  9. data/CHANGES.txt +361 -2
  10. data/CONTRIBUTORS-GUIDE.md +49 -0
  11. data/Gemfile +2 -0
  12. data/LICENSE +3 -36
  13. data/NOTICE.txt +5 -0
  14. data/README.md +59 -127
  15. data/Rakefile +27 -3
  16. data/ext/murmurhash/MurmurHash3.java +302 -0
  17. data/gemfiles/faraday_after_0.13.gemfile +7 -0
  18. data/gemfiles/faraday_before_0.13.gemfile +8 -0
  19. data/lib/murmurhash/base.rb +58 -0
  20. data/lib/murmurhash/murmurhash.jar +0 -0
  21. data/lib/murmurhash/murmurhash_mri.rb +3 -0
  22. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +130 -0
  23. data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
  24. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +137 -0
  25. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +53 -0
  26. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +178 -0
  27. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  28. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  29. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  30. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  31. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  32. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  33. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  34. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  35. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +45 -0
  36. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +35 -0
  37. data/lib/splitclient-rb/cache/repositories/events_repository.rb +61 -0
  38. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  39. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  40. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +56 -0
  41. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +57 -0
  42. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +23 -0
  43. data/lib/splitclient-rb/cache/repositories/repository.rb +24 -0
  44. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  45. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +124 -0
  46. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +296 -0
  47. data/lib/splitclient-rb/cache/routers/impression_router.rb +60 -0
  48. data/lib/splitclient-rb/cache/senders/events_sender.rb +42 -0
  49. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  50. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  51. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  52. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +95 -0
  53. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +52 -0
  54. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  55. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  56. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  57. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  58. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  59. data/lib/splitclient-rb/clients/split_client.rb +530 -0
  60. data/lib/splitclient-rb/constants.rb +16 -0
  61. data/lib/splitclient-rb/engine/api/client.rb +87 -0
  62. data/lib/splitclient-rb/engine/api/events.rb +57 -0
  63. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +58 -0
  64. data/lib/splitclient-rb/engine/api/impressions.rb +79 -0
  65. data/lib/splitclient-rb/engine/api/segments.rb +78 -0
  66. data/lib/splitclient-rb/engine/api/splits.rb +139 -0
  67. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  68. data/lib/splitclient-rb/engine/auth_api_client.rb +100 -0
  69. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  70. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  71. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  72. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  73. data/lib/{splitclient-engine → splitclient-rb/engine}/evaluator/splitter.rb +35 -22
  74. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  75. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  76. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  77. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  78. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  79. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  80. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  81. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  82. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/all_keys_matcher.rb +10 -21
  83. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +47 -0
  84. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  85. data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/combiners.rb +4 -6
  86. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +80 -0
  87. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +20 -0
  88. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +16 -0
  89. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +43 -0
  90. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +26 -0
  91. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +42 -0
  92. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +37 -0
  93. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +44 -0
  94. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  95. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +16 -0
  96. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +43 -0
  97. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  98. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  99. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +43 -0
  100. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  101. data/lib/splitclient-rb/engine/matchers/matcher.rb +52 -0
  102. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +29 -0
  103. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +47 -0
  104. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +22 -0
  105. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  106. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  107. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  108. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +27 -0
  109. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +40 -0
  110. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +28 -0
  111. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
  112. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +66 -0
  113. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  114. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  116. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  117. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  118. data/lib/splitclient-rb/engine/models/label.rb +10 -0
  119. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  120. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  121. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  122. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +16 -0
  123. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  124. data/lib/splitclient-rb/engine/models/split.rb +17 -0
  125. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  126. data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
  127. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  128. data/lib/splitclient-rb/engine/parser/condition.rb +271 -0
  129. data/lib/splitclient-rb/engine/parser/evaluator.rb +112 -0
  130. data/lib/{splitclient-engine → splitclient-rb/engine}/parser/partition.rb +2 -4
  131. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  132. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  133. data/lib/splitclient-rb/engine/sync_manager.rb +183 -0
  134. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  135. data/lib/splitclient-rb/exceptions.rb +26 -0
  136. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  137. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  138. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  139. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  140. data/lib/splitclient-rb/helpers/util.rb +26 -0
  141. data/lib/splitclient-rb/managers/split_manager.rb +121 -0
  142. data/lib/splitclient-rb/spec.rb +9 -0
  143. data/lib/splitclient-rb/split_config.rb +591 -47
  144. data/lib/splitclient-rb/split_factory.rb +284 -0
  145. data/lib/splitclient-rb/split_factory_builder.rb +7 -0
  146. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  147. data/lib/splitclient-rb/split_logger.rb +23 -0
  148. data/lib/splitclient-rb/sse/event_source/client.rb +264 -0
  149. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  150. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  151. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  152. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  153. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  154. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  155. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  156. data/lib/splitclient-rb/sse/workers/splits_worker.rb +153 -0
  157. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  158. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  159. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  160. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  161. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  162. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  163. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  164. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  165. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  166. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  167. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  168. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  169. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  170. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  171. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  172. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  173. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  174. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  175. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  176. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  177. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  178. data/lib/splitclient-rb/utilitites.rb +49 -0
  179. data/lib/splitclient-rb/validators.rb +361 -0
  180. data/lib/splitclient-rb/version.rb +1 -1
  181. data/lib/splitclient-rb.rb +177 -25
  182. data/sonar-project.properties +6 -0
  183. data/splitclient-rb.gemspec +53 -26
  184. data/tasks/benchmark_get_treatment.rake +31 -17
  185. data/tasks/irb.rake +6 -0
  186. metadata +411 -86
  187. data/NEWS +0 -9
  188. data/lib/splitclient-cache/local_store.rb +0 -45
  189. data/lib/splitclient-engine/impressions/impressions.rb +0 -79
  190. data/lib/splitclient-engine/matchers/between_matcher.rb +0 -48
  191. data/lib/splitclient-engine/matchers/combining_matcher.rb +0 -94
  192. data/lib/splitclient-engine/matchers/equal_to_matcher.rb +0 -48
  193. data/lib/splitclient-engine/matchers/greater_than_or_equal_to_matcher.rb +0 -48
  194. data/lib/splitclient-engine/matchers/less_than_or_equal_to_matcher.rb +0 -48
  195. data/lib/splitclient-engine/matchers/negation_matcher.rb +0 -54
  196. data/lib/splitclient-engine/matchers/user_defined_segment_matcher.rb +0 -61
  197. data/lib/splitclient-engine/matchers/whitelist_matcher.rb +0 -64
  198. data/lib/splitclient-engine/metrics/binary_search_latency_tracker.rb +0 -122
  199. data/lib/splitclient-engine/metrics/metrics.rb +0 -158
  200. data/lib/splitclient-engine/parser/condition.rb +0 -143
  201. data/lib/splitclient-engine/parser/segment.rb +0 -84
  202. data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
  203. data/lib/splitclient-engine/parser/split.rb +0 -68
  204. data/lib/splitclient-engine/parser/split_adapter.rb +0 -433
  205. data/lib/splitclient-engine/parser/split_parser.rb +0 -139
  206. data/lib/splitclient-engine/partitions/treatments.rb +0 -40
  207. data/lib/splitclient-rb/split_client.rb +0 -156
  208. data/lib/splitclient-rb_utilitites.rb +0 -26
  209. data/tasks/console.rake +0 -4
  210. data/tasks/rspec.rake +0 -3
@@ -1,433 +0,0 @@
1
- require 'json'
2
- require 'thread'
3
- require 'faraday/http_cache'
4
- require 'bundler/vendor/net/http/persistent'
5
- require 'faraday_middleware'
6
-
7
-
8
- module SplitIoClient
9
-
10
- #
11
- # acts as an api adapater to connect to split endpoints
12
- # uses a configuration object that can be modified when creating the client instance
13
- # also, uses safe threads to execute fetches and post give the time execution values from the config
14
- #
15
- class SplitAdapter < NoMethodError
16
- #
17
- # handler for impressions
18
- attr_reader :impressions
19
-
20
- #
21
- # handler for metrics
22
- attr_reader :metrics
23
-
24
- #
25
- # handler for parsed splits
26
- attr_reader :parsed_splits
27
-
28
- #
29
- # handeler for parsed segments
30
- attr_reader :parsed_segments
31
-
32
- attr_reader :impressions_producer
33
-
34
- #
35
- # Creates a new split api adapter instance that consumes split api endpoints
36
- #
37
- # @param api_key [String] the API key for your split account
38
- #
39
- # @return [SplitIoClient] split.io client instance
40
- def initialize(api_key, config)
41
-
42
- @api_key = api_key
43
- @config = config
44
- @parsed_splits = SplitParser.new(@config.logger)
45
- @parsed_segments = SegmentParser.new(@config.logger)
46
- @impressions = Impressions.new(100)
47
- @metrics = Metrics.new(100)
48
-
49
- @api_client = Faraday.new do |builder|
50
- builder.use Faraday::HttpCache, store: @config.local_store
51
- builder.use FaradayMiddleware::Gzip
52
- builder.adapter :net_http_persistent
53
- end
54
-
55
- @splits_consumer = create_splits_api_consumer
56
- @segments_consumer = create_segments_api_consumer
57
- @metrics_producer = create_metrics_api_producer
58
- @impressions_producer = create_impressions_api_producer
59
- end
60
-
61
- #
62
- # creates a safe thread that will be executing api calls
63
- # for fetching splits and segments give the execution time
64
- # provided within the configuration
65
- #
66
- # @return [void]
67
- def create_splits_api_consumer
68
- Thread.new do
69
- loop do
70
- begin
71
- #splits fetcher
72
- splits_arr = []
73
- data = get_splits(@parsed_splits.since)
74
- data[:splits].each do |split|
75
- splits_arr << SplitIoClient::Split.new(split)
76
- end
77
-
78
- if @parsed_splits.is_empty?
79
- @parsed_splits.splits = splits_arr
80
- else
81
- refresh_splits(splits_arr)
82
- end
83
- @parsed_splits.since = data[:till]
84
-
85
- random_interval = randomize_interval @config.features_refresh_rate
86
- sleep(random_interval)
87
- rescue StandardError => error
88
- @config.log_found_exception(__method__.to_s, error)
89
- end
90
- end
91
- end
92
- end
93
-
94
- def create_segments_api_consumer
95
- Thread.new do
96
- loop do
97
- begin
98
- #segments fetcher
99
- segments_arr = []
100
- segment_data = get_segments(@parsed_splits.get_used_segments)
101
- segment_data.each do |segment|
102
- segments_arr << SplitIoClient::Segment.new(segment)
103
- end
104
- if @parsed_segments.is_empty?
105
- @parsed_segments.segments = segments_arr
106
- @parsed_segments.segments.map { |s| s.refresh_users(s.added, s.removed) }
107
- else
108
- refresh_segments(segments_arr)
109
- end
110
-
111
- random_interval = randomize_interval @config.segments_refresh_rate
112
- sleep(random_interval)
113
- rescue StandardError => error
114
- @config.log_found_exception(__method__.to_s, error)
115
- end
116
- end
117
- end
118
- end
119
-
120
- #
121
- # helper method to execute a get request to the provided endpoint
122
- #
123
- # @param path [string] api endpoint path
124
- # @param params [object] hash of params that will be added to the request
125
- #
126
- # @return [object] response to the request
127
- def call_api(path, params = {})
128
- @api_client.get @config.base_uri + path, params do |req|
129
- req.headers['Authorization'] = 'Bearer ' + @api_key
130
- req.headers['SplitSDKVersion'] = SplitIoClient::SplitClient.sdk_version
131
- req.headers['SplitSDKMachineName'] = @config.machine_name
132
- req.headers['SplitSDKMachineIP'] = @config.machine_ip
133
- req.headers['Accept-Encoding'] = 'gzip'
134
- req.options.open_timeout = @config.connection_timeout
135
- req.options.timeout = @config.read_timeout
136
- @config.logger.debug("GET #{@config.base_uri + path}") if @config.debug_enabled
137
- end
138
- end
139
-
140
- #
141
- # helper method to execute a post request to the provided endpoint
142
- #
143
- # @param path [string] api endpoint path
144
- # @param params [object] hash of params that will be added to the request
145
- #
146
- # @return [object] response to the request
147
- def post_api(path, param)
148
- @api_client.post (@config.base_uri + path) do |req|
149
- req.headers['Authorization'] = 'Bearer ' + @api_key
150
- req.headers['Content-Type'] = 'application/json'
151
- req.headers['SplitSDKVersion'] = SplitIoClient::SplitClient.sdk_version
152
- req.headers['SplitSDKMachineName'] = @config.machine_name
153
- req.headers['SplitSDKMachineIP'] = @config.machine_ip
154
- req.body = param.to_json
155
- req.options.timeout = @config.read_timeout
156
- req.options.open_timeout = @config.connection_timeout
157
- @config.logger.debug("POST #{@config.base_uri + path} #{req.body}") if @config.debug_enabled
158
- end
159
- end
160
-
161
- #
162
- # helper method to fetch splits by using the appropriate api endpoint
163
- #
164
- # @param since [int] since value for the last fetch
165
- #
166
- # @return splits [object] splits structure in json format
167
- def get_splits(since)
168
- result = nil
169
- start = Time.now
170
- prefix = 'splitChangeFetcher'
171
-
172
- splits = call_api('/splitChanges', {:since => since})
173
-
174
- if splits.status / 100 == 2
175
- result = JSON.parse(splits.body, symbolize_names: true)
176
- @metrics.count(prefix + '.status.' + splits.status.to_s, 1)
177
- @config.logger.info("#{result[:splits].length} splits retrieved.")
178
- @config.logger.debug("#{result}") if @config.debug_enabled
179
- else
180
- @config.logger.error('Unexpected result from API call')
181
- @metrics.count(prefix + '.status.' + splits.status.to_s, 1)
182
- end
183
-
184
- latency = (Time.now - start) * 1000.0
185
- @metrics.time(prefix + '.time', latency)
186
-
187
- result
188
- end
189
-
190
- #
191
- # helper method to refresh splits values after a new fetch with changes
192
- #
193
- # @param splits_arr [object] array of splits to refresh
194
- #
195
- # @return [void]
196
- def refresh_splits(splits_arr)
197
- feature_names = splits_arr.map { |s| s.name }
198
- @parsed_splits.splits.delete_if { |sp| feature_names.include?(sp.name) }
199
- @parsed_splits.splits += splits_arr
200
- end
201
-
202
- #
203
- # helper method to fetch segments by using the appropriate api endpoint
204
- #
205
- # @param names [object] array of segment names that must be fetched
206
- #
207
- # @return segments [object] segments structure in json format
208
- def get_segments(names)
209
- segments = []
210
- start = Time.now
211
- prefix = 'segmentChangeFetcher'
212
-
213
- names.each do |name|
214
- curr_segment = @parsed_segments.get_segment(name)
215
- since = curr_segment.nil? ? -1 : curr_segment.till
216
-
217
- while true
218
- segment = call_api('/segmentChanges/' + name, {:since => since})
219
-
220
- if segment.status / 100 == 2
221
- segment_content = JSON.parse(segment.body, symbolize_names: true)
222
- @parsed_segments.since = segment_content[:till]
223
- @metrics.count(prefix + '.status.' + segment.status.to_s, 1)
224
- @config.logger.info("\'#{segment_content[:name]}\' segment retrieved.")
225
- @config.logger.debug("#{segment_content}") if @config.debug_enabled
226
- segments << segment_content
227
- else
228
- @config.logger.error('Unexpected result from API call')
229
- @metrics.count(prefix + '.status.' + segment.status.to_s, 1)
230
- end
231
- break if (since.to_i >= @parsed_segments.since.to_i)
232
- since = @parsed_segments.since
233
- end
234
- end
235
-
236
- latency = (Time.now - start) * 1000.0
237
- @metrics.time(prefix + '.time', latency)
238
-
239
- segments
240
- end
241
-
242
- #
243
- # helper method to refresh segments values after a new fetch with changes
244
- #
245
- # @param segments_arr [object] array of segments to refresh
246
- #
247
- # @return [void]
248
- def refresh_segments(segments_arr)
249
- segment_names = @parsed_segments.segments.map { |s| s.name }
250
- segments_arr.each do |s|
251
- if segment_names.include?(s.name)
252
- segment_to_update = @parsed_segments.get_segment(s.name)
253
- segment_to_update.refresh_users(s.added, s.removed)
254
- else
255
- @parsed_segments.segments << s
256
- end
257
- end
258
- end
259
-
260
- #
261
- # @return parsed_splits [object] parsed splits for this adapter
262
- def parsed_splits
263
- @parsed_splits
264
- end
265
-
266
- #
267
- # @return parsed_segments [object] parsed segments for this adapter
268
- def parsed_segments
269
- @parsed_segments
270
- end
271
-
272
- #
273
- # creates two safe threads that will be executing api calls
274
- # for posting impressions and metrics given the execution time
275
- # provided within the configuration
276
- #
277
-
278
- def create_metrics_api_producer
279
- Thread.new do
280
- loop do
281
- begin
282
- #post captured metrics
283
- post_metrics
284
-
285
- random_interval = randomize_interval @config.metrics_refresh_rate
286
- sleep(random_interval)
287
- rescue StandardError => error
288
- @config.log_found_exception(__method__.to_s, error)
289
- end
290
- end
291
- end
292
- end
293
-
294
- def create_impressions_api_producer
295
- Thread.new do
296
- loop do
297
- begin
298
- #post captured impressions
299
- post_impressions
300
-
301
- random_interval = randomize_interval @config.impressions_refresh_rate
302
- sleep(random_interval)
303
- rescue StandardError => error
304
- @config.log_found_exception(__method__.to_s, error)
305
- end
306
- end
307
- end
308
- end
309
-
310
- #
311
- # creates the appropriate json data for the cached impressions values
312
- # and then sends them to the appropriate api endpoint with a valid body format
313
- #
314
- # @return [void]
315
- def post_impressions
316
- if @impressions.queue.empty?
317
- @config.logger.info('No impressions to report.')
318
- else
319
- popped_impressions = @impressions.clear
320
- test_impression_array = []
321
- popped_impressions.each do |i|
322
- filtered = []
323
- keys_seen = []
324
-
325
- impressions = i[:impressions]
326
- impressions.each do |imp|
327
- if keys_seen.include?(imp.key)
328
- next
329
- end
330
- keys_seen << imp.key
331
- filtered << imp
332
- end
333
-
334
- if filtered.empty?
335
- @config.logger.info('No impressions to report post filtering.')
336
- else
337
- test_impression = {}
338
- key_impressions = []
339
-
340
- filtered.each do |f|
341
- key_impressions << {keyName: f.key, treatment: f.treatment, time: f.time.to_i}
342
- end
343
-
344
- test_impression = {testName: i[:feature], keyImpressions: key_impressions}
345
- test_impression_array << test_impression
346
- end
347
- end
348
-
349
- res = post_api('/testImpressions/bulk', test_impression_array)
350
- if res.status / 100 != 2
351
- @config.logger.error("Unexpected status code while posting impressions: #{res.status}")
352
- else
353
- @config.logger.info("Impressions reported.")
354
- @config.logger.debug("#{test_impression_array}")if @config.debug_enabled
355
- end
356
- end
357
- end
358
-
359
- #
360
- # creates the appropriate json data for the cached metrics values
361
- # include latencies, counts and gauges
362
- # and then sends them to the appropriate api endpoint with a valida body format
363
- #
364
- # @return [void]
365
- def post_metrics
366
- clear = true
367
- if @metrics.latencies.empty?
368
- @config.logger.info('No latencies to report.')
369
- else
370
- @metrics.latencies.each do |l|
371
- metrics_time = {}
372
- metrics_time = {name: l[:operation], latencies: l[:latencies]}
373
- res = post_api('/metrics/time', metrics_time)
374
- if res.status / 100 != 2
375
- @config.logger.error("Unexpected status code while posting time metrics: #{res.status}")
376
- clear = false
377
- else
378
- @config.logger.info("Metric time reported.")
379
- @config.logger.debug("#{metrics_time}") if @config.debug_enabled
380
- end
381
- end
382
- end
383
- @metrics.latencies.clear if clear
384
-
385
- clear = true
386
- if @metrics.counts.empty?
387
- @config.logger.info('No counts to report.')
388
- else
389
- @metrics.counts.each do |c|
390
- metrics_count = {}
391
- metrics_count = {name: c[:name], delta: c[:delta].sum}
392
- res = post_api('/metrics/counter', metrics_count)
393
- if res.status / 100 != 2
394
- @config.logger.error("Unexpected status code while posting count metrics: #{res.status}")
395
- clear = false
396
- else
397
- @config.logger.info("Metric counts reported.")
398
- @config.logger.debug("#{metrics_count}") if @config.debug_enabled
399
- end
400
- end
401
- end
402
- @metrics.counts.clear if clear
403
-
404
- clear = true
405
- if @metrics.gauges.empty?
406
- @config.logger.info('No gauges to report.')
407
- else
408
- @metrics.gauges.each do |g|
409
- metrics_gauge = {}
410
- metrics_gauge = {name: g[:name], value: g[:gauge].value}
411
- res = post_api('/metrics/gauge', metrics_gauge)
412
- if res.status / 100 != 2
413
- @config.logger.error("Unexpected status code while posting gauge metrics: #{res.status}")
414
- clear = false
415
- else
416
- @config.logger.info("Metric gauge reported.")
417
- @config.logger.debug("#{metrics_gauge}") if @config.debug_enabled
418
- end
419
- end
420
- end
421
- @metrics.gauges.clear if clear
422
-
423
- end
424
-
425
- private
426
-
427
- def randomize_interval(interval)
428
- @random_generator ||= Random.new
429
- random_factor = @random_generator.rand(50..100)/100.0
430
- interval * random_factor
431
- end
432
- end
433
- end
@@ -1,139 +0,0 @@
1
- module SplitIoClient
2
- #
3
- # helper class to parse fetched splits
4
- #
5
- class SplitParser < NoMethodError
6
- #
7
- # since value for splitChanges last fetch
8
- attr_accessor :since
9
-
10
- #
11
- # till value for splitChanges last fetch
12
- attr_accessor :till
13
-
14
- #
15
- # splits data
16
- attr_accessor :splits
17
-
18
- #
19
- # splits segments data
20
- attr_accessor :segments
21
-
22
- def initialize(logger)
23
- @splits = []
24
- @since = -1
25
- @till = -1
26
- @logger = logger
27
- end
28
-
29
- #
30
- # gets all the split names retrived from the endpoint
31
- #
32
- # @return [object] array of split names
33
- def get_split_names
34
- @splits.map { |s| s.name }
35
- end
36
-
37
- #
38
- # @return [boolean] true if the splits content is empty false otherwise
39
- def is_empty?
40
- @splits.empty? ? true : false
41
- end
42
-
43
- #
44
- # gets all the segment names that are used within the retrieved splits
45
- #
46
- # @return [object] array of segment names
47
- def get_used_segments
48
- segment_names = []
49
-
50
- @splits.each { |s|
51
- s.conditions.each { |c|
52
- c.matchers.each { |m|
53
- m[:userDefinedSegmentMatcherData].each { |seg, name|
54
- segment_names << name
55
- } unless m[:userDefinedSegmentMatcherData].nil?
56
- } unless c.matchers.nil?
57
- }
58
- }
59
- segment_names.uniq
60
- end
61
-
62
- #
63
- # gets a split parsed object by name
64
- #
65
- # @param name [string] name of the split
66
- #
67
- # @return split [object] split object
68
- def get_split(name)
69
- @splits.find { |s| s.name == name }
70
- end
71
-
72
- #
73
- # gets the treatment for the given combination of user key and split name
74
- # using all parsed data for the splits
75
- #
76
- # @param id [string] user key
77
- # @param name [string] split name
78
- # @param default_treatment [string] default treatment value to be returned
79
- #
80
- # @return treatment [object] treatment for this user key, split pair
81
- def get_split_treatment(id, name, default_treatment, attributes = nil)
82
- split = get_split(name)
83
- attribute_matchers = ["ATTR_WHITELIST", "EQUAL_TO", "GREATER_THAN_OR_EQUAL_TO", "LESS_THAN_OR_EQUAL_TO", "BETWEEN"]
84
-
85
- if !split.is_empty? && split.status == 'ACTIVE' && !split.killed?
86
- split.conditions.each do |c|
87
- unless c.is_empty?
88
- matcher = get_matcher_type(c)
89
- matches = attribute_matchers.include?(matcher.matcher_type) ? matcher.match?(attributes) : matcher.match?(id)
90
- if matches
91
- result = Splitter.get_treatment(id, split.seed, c.partitions) #'true match - running split'
92
- if result.nil?
93
- return default_treatment
94
- else
95
- return result
96
- end
97
- end
98
- end
99
- end
100
- end
101
-
102
- default_treatment
103
- end
104
-
105
- #
106
- # gets the matcher type from a condition object
107
- #
108
- # @param contidion [object] a condition object
109
- #
110
- # @return matcher [object] the matcher object for the given condition
111
- def get_matcher_type(condition)
112
- final_matcher = nil
113
-
114
- case condition.matcher
115
- when 'ALL_KEYS'
116
- final_matcher = AllKeysMatcher.new
117
- when 'IN_SEGMENT'
118
- segment = @segments.get_segment(condition.matcher_segment)
119
- final_matcher = segment.is_empty? ? UserDefinedSegmentMatcher.new(nil) : UserDefinedSegmentMatcher.new(segment)
120
- when 'WHITELIST'
121
- final_matcher = WhitelistMatcher.new(condition.matcher_whitelist)
122
- when 'EQUAL_TO'
123
- final_matcher = EqualToMatcher.new(condition.matcher_equal)
124
- when 'GREATER_THAN_OR_EQUAL_TO'
125
- final_matcher = GreaterThanOrEqualToMatcher.new(condition.matcher_greater_than_or_equal)
126
- when 'LESS_THAN_OR_EQUAL_TO'
127
- final_matcher = LessThanOrEqualToMatcher.new(condition.matcher_less_than_or_equal)
128
- when 'BETWEEN'
129
- final_matcher = BetweenMatcher.new(condition.matcher_between)
130
- else
131
- @logger.error('Invalid matcher type')
132
- end
133
-
134
- final_matcher
135
- end
136
-
137
- end
138
-
139
- end
@@ -1,40 +0,0 @@
1
- module SplitIoClient
2
-
3
- #
4
- # represents the possible return values for a treatment
5
- #
6
- class Treatments < NoMethodError
7
-
8
- # Constants to represent treatment values
9
- CONTROL = 'control'
10
- OFF = 'off'
11
- ON = 'on'
12
-
13
- # get the actual value for the given treatment type
14
- #
15
- # @param type [string] treatment type
16
- #
17
- # @return [Treatment] treatment type value
18
- def self.get_type(type)
19
- case type
20
- when 'on'
21
- return ON
22
- when 'off', 'control'
23
- return CONTROL
24
- else # default return off
25
- return CONTROL
26
- end
27
- end
28
-
29
- # checks if the give treatment matches control type
30
- #
31
- # @param type [string] treatment type
32
- #
33
- # @return [boolean] true if matches, false otherwise
34
- def self.is_control?(treatment)
35
- get_type(treatment).equal?(CONTROL) ? true : false
36
- end
37
-
38
- end
39
-
40
- end