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
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Senders
6
+ class ImpressionsSender
7
+ def initialize(impressions_repository, config, impressions_api)
8
+ @impressions_repository = impressions_repository
9
+ @config = config
10
+ @impressions_api = impressions_api
11
+ end
12
+
13
+ def call
14
+ impressions_thread
15
+ end
16
+
17
+ private
18
+
19
+ def impressions_thread
20
+ @config.threads[:impressions_sender] = Thread.new do
21
+ begin
22
+ @config.logger.info('Starting impressions service')
23
+
24
+ loop do
25
+ post_impressions(false)
26
+
27
+ sleep(SplitIoClient::Utilities.randomize_interval(@config.impressions_refresh_rate))
28
+ end
29
+ rescue SplitIoClient::SDKShutdownException
30
+ post_impressions
31
+
32
+ @config.logger.info('Posting impressions due to shutdown')
33
+ end
34
+ end
35
+ end
36
+
37
+ def post_impressions(fetch_all_impressions = true)
38
+ formatted_impressions = ImpressionsFormatter.new(@impressions_repository)
39
+ .call(fetch_all_impressions)
40
+
41
+ impressions_api.post(formatted_impressions)
42
+ rescue StandardError => e
43
+ @config.log_found_exception(__method__.to_s, e)
44
+ end
45
+
46
+ def impressions_api
47
+ @impressions_api
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Senders
6
+ class ImpressionsSenderAdapter
7
+ extend Forwardable
8
+ def_delegators :@sender, :record_uniques_key, :record_impressions_count
9
+
10
+ def initialize(config, telemetry_api, impressions_api)
11
+ @sender = case config.telemetry_adapter.class.to_s
12
+ when 'SplitIoClient::Cache::Adapters::RedisAdapter'
13
+ Cache::Senders::RedisImpressionsSender.new(config)
14
+ else
15
+ Cache::Senders::MemoryImpressionsSender.new(config, telemetry_api, impressions_api)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Senders
6
+ class LocalhostRepoCleaner
7
+ def initialize(impressions_repository, events_repository, config)
8
+ @impressions_repository = impressions_repository
9
+ @events_repository = events_repository
10
+ @config = config
11
+ end
12
+
13
+ def call
14
+ if ENV['SPLITCLIENT_ENV'] == 'test'
15
+ clear_repositories
16
+ else
17
+ cleaner_thread
18
+
19
+ if defined?(PhusionPassenger)
20
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
21
+ cleaner_thread if forked
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def cleaner_thread
30
+ @config.threads[:repo_cleaner] = Thread.new do
31
+ @config.logger.info('Starting repositories cleanup service')
32
+ loop do
33
+ clear_repositories
34
+
35
+ sleep(SplitIoClient::Utilities.randomize_interval(@config.features_refresh_rate))
36
+ end
37
+ end
38
+ end
39
+
40
+ def clear_repositories
41
+ @impressions_repository.clear
42
+ @events_repository.clear
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Stores
6
+ class LocalhostSplitBuilder
7
+ class << self
8
+ def build_splits(splits)
9
+ splits.map do |feature, treatments|
10
+ build_split(feature, treatments)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def build_split(feature, treatments)
17
+ {
18
+ name: feature,
19
+ status: 'ACTIVE',
20
+ killed: false,
21
+ trafficAllocation: 100,
22
+ seed: 2_089_907_429,
23
+ defaultTreatment: 'control_treatment',
24
+ configurations: build_configurations(treatments),
25
+ conditions: build_conditions(treatments),
26
+ prerequisites: []
27
+ }
28
+ end
29
+
30
+ def build_configurations(treatments)
31
+ treatments.reduce({}) do |hash, treatment|
32
+ hash.merge(treatment[:treatment].to_sym => treatment[:config])
33
+ end
34
+ end
35
+
36
+ def build_conditions(treatments)
37
+ conditions = treatments.map do |treatment|
38
+ if treatment[:keys]
39
+ build_whitelist_treatment(treatment[:treatment], Array(treatment[:keys]))
40
+ else
41
+ build_rollout_treatment
42
+ end
43
+ .merge(partitions: build_partitions(treatment[:treatment], treatments))
44
+ end
45
+
46
+ conditions.sort_by { |condition| condition[:conditionType] }.reverse!
47
+ end
48
+
49
+ def build_whitelist_treatment(treatment_name, whitelist_keys)
50
+ {
51
+ conditionType: 'WHITELIST',
52
+ matcherGroup: {
53
+ combiner: 'AND',
54
+ matchers: [{
55
+ keySelector: nil,
56
+ matcherType: 'WHITELIST',
57
+ negate: false,
58
+ whitelistMatcherData: {
59
+ whitelist: whitelist_keys
60
+ }
61
+ }]
62
+ },
63
+ label: "whitelisted #{treatment_name}"
64
+ }
65
+ end
66
+
67
+ def build_rollout_treatment
68
+ {
69
+ conditionType: 'ROLLOUT',
70
+ matcherGroup: {
71
+ combiner: 'AND',
72
+ matchers: [
73
+ {
74
+ matcherType: 'ALL_KEYS',
75
+ negate: false
76
+ }
77
+ ]
78
+ },
79
+ label: 'default rule'
80
+ }
81
+ end
82
+
83
+ def build_partitions(current_treatment_name, treatments)
84
+ treatments.map do |treatment|
85
+ {
86
+ treatment: treatment[:treatment],
87
+ size: treatment[:treatment] == current_treatment_name ? 100 : 0
88
+ }
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Cache
5
+ module Stores
6
+ class LocalhostSplitStore
7
+ require 'yaml'
8
+ attr_reader :splits_repository
9
+
10
+ def initialize(splits_repository, config, status_manager = nil)
11
+ @splits_repository = splits_repository
12
+ @config = config
13
+ @status_manager = status_manager
14
+ end
15
+
16
+ def call
17
+ if ENV['SPLITCLIENT_ENV'] == 'test'
18
+ store_splits
19
+ else
20
+ splits_thread
21
+
22
+ if defined?(PhusionPassenger)
23
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
24
+ splits_thread if forked
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def splits_thread
33
+ @config.threads[:split_store] = Thread.new do
34
+ @config.logger.info('Starting feature flags fetcher service')
35
+ loop do
36
+ store_splits
37
+
38
+ sleep(StoreUtils.random_interval(@config.features_refresh_rate))
39
+ end
40
+ end
41
+ end
42
+
43
+ def store_splits
44
+ load_features.each do |split|
45
+ store_split(split)
46
+ end
47
+
48
+ @status_manager.ready! if @status_manager
49
+ rescue StandardError => e
50
+ @config.logger.error('Error while parsing the split file. ' \
51
+ 'Check that the input file matches the expected format')
52
+ @config.log_found_exception(__method__.to_s, e)
53
+ end
54
+
55
+ def store_split(split)
56
+ @config.logger.debug("storing feature flag (#{split[:name]})") if @config.debug_enabled
57
+
58
+ @splits_repository.update([split], [], -1)
59
+ end
60
+
61
+ def load_features
62
+ yaml_extensions = ['.yml', '.yaml']
63
+ if yaml_extensions.include? File.extname(@config.split_file)
64
+ parse_yaml_features
65
+ else
66
+ @config.logger.warn('Localhost mode: .split mocks ' \
67
+ 'will be deprecated soon in favor of YAML files, which provide more ' \
68
+ 'targeting power. Take a look in our documentation.')
69
+
70
+ parse_plain_text_features
71
+ end
72
+ end
73
+
74
+ def parse_plain_text_features
75
+ splits = File.open(@config.split_file).each_with_object({}) do |line, memo|
76
+ feature, treatment = line.strip.split(' ')
77
+
78
+ next if line.start_with?('#') || line.strip.empty?
79
+
80
+ memo[feature] = [{ treatment: treatment }]
81
+ end
82
+
83
+ LocalhostSplitBuilder.build_splits(splits)
84
+ end
85
+
86
+ def parse_yaml_features
87
+ splits = YAML.safe_load(File.read(@config.split_file)).each_with_object({}) do |feature, memo|
88
+ feat_symbolized_keys = symbolize_feat_keys(feature)
89
+
90
+ feat_name = feature.keys.first
91
+
92
+ if memo[feat_name]
93
+ memo[feat_name] << feat_symbolized_keys
94
+ else
95
+ memo[feat_name] = [feat_symbolized_keys]
96
+ end
97
+ end
98
+
99
+ LocalhostSplitBuilder.build_splits(splits)
100
+ end
101
+
102
+ def symbolize_feat_keys(yaml_feature)
103
+ yaml_feature.values.first.each_with_object({}) do |(k, v), memo|
104
+ memo[k.to_sym] = k == 'config' ? v.to_json : v
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,13 @@
1
+ module SplitIoClient
2
+ module Cache
3
+ module Stores
4
+ class StoreUtils
5
+ def self.random_interval(interval)
6
+ random_factor = Random.new.rand(50..100) / 100.0
7
+
8
+ interval * random_factor
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end