splitclient-rb 6.3.0 → 8.11.0

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 (192) hide show
  1. checksums.yaml +4 -4
  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 +4 -0
  7. data/.rubocop.yml +46 -3
  8. data/CHANGES.txt +158 -11
  9. data/CONTRIBUTORS-GUIDE.md +49 -0
  10. data/LICENSE +169 -13
  11. data/NOTICE.txt +5 -0
  12. data/README.md +67 -27
  13. data/Rakefile +1 -8
  14. data/ext/murmurhash/3_x64_128.c +117 -0
  15. data/ext/murmurhash/murmurhash.c +5 -1
  16. data/lib/murmurhash/murmurhash.jar +0 -0
  17. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
  18. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +4 -0
  19. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +7 -0
  20. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +12 -4
  21. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  22. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  23. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  24. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  25. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  26. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  27. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  28. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  29. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +26 -14
  30. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +9 -14
  31. data/lib/splitclient-rb/cache/repositories/events_repository.rb +31 -10
  32. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  33. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  34. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +22 -23
  35. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +15 -22
  36. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +6 -31
  37. data/lib/splitclient-rb/cache/repositories/repository.rb +6 -5
  38. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  39. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +46 -6
  40. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +232 -43
  41. data/lib/splitclient-rb/cache/routers/impression_router.rb +24 -22
  42. data/lib/splitclient-rb/cache/senders/events_sender.rb +12 -29
  43. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  44. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  45. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  46. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +27 -13
  47. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +11 -25
  48. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  49. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  50. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  51. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  52. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  53. data/lib/splitclient-rb/clients/split_client.rb +385 -138
  54. data/lib/splitclient-rb/constants.rb +16 -0
  55. data/lib/splitclient-rb/engine/api/client.rb +38 -43
  56. data/lib/splitclient-rb/engine/api/events.rb +19 -11
  57. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
  58. data/lib/splitclient-rb/engine/api/impressions.rb +49 -14
  59. data/lib/splitclient-rb/engine/api/segments.rb +31 -24
  60. data/lib/splitclient-rb/engine/api/splits.rb +108 -33
  61. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  62. data/lib/splitclient-rb/engine/auth_api_client.rb +96 -0
  63. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  64. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  65. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  66. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  67. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  68. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  69. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  70. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  71. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  72. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  73. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  74. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  75. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
  76. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
  77. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  78. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +10 -8
  79. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +2 -6
  80. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +1 -5
  81. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
  82. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +6 -5
  83. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
  84. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
  85. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
  86. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  87. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +1 -5
  88. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
  89. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  90. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  91. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
  92. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  93. data/lib/splitclient-rb/engine/matchers/matcher.rb +22 -0
  94. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
  95. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
  96. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +2 -6
  97. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  98. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  99. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  100. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
  101. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
  102. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
  103. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
  104. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
  105. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  106. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  107. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  108. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  109. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  110. data/lib/splitclient-rb/engine/models/label.rb +3 -0
  111. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  112. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  113. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  114. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  116. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  117. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  118. data/lib/splitclient-rb/engine/parser/condition.rb +81 -20
  119. data/lib/splitclient-rb/engine/parser/evaluator.rb +40 -51
  120. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  121. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  122. data/lib/splitclient-rb/engine/sync_manager.rb +180 -0
  123. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  124. data/lib/splitclient-rb/exceptions.rb +20 -1
  125. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  126. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  127. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  128. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  129. data/lib/splitclient-rb/helpers/util.rb +26 -0
  130. data/lib/splitclient-rb/managers/split_manager.rb +58 -20
  131. data/lib/splitclient-rb/spec.rb +9 -0
  132. data/lib/splitclient-rb/split_config.rb +336 -54
  133. data/lib/splitclient-rb/split_factory.rb +219 -33
  134. data/lib/splitclient-rb/split_factory_builder.rb +1 -22
  135. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  136. data/lib/splitclient-rb/split_logger.rb +9 -10
  137. data/lib/splitclient-rb/sse/event_source/client.rb +263 -0
  138. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  139. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  140. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  141. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  142. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  143. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  144. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  145. data/lib/splitclient-rb/sse/workers/splits_worker.rb +149 -0
  146. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  147. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  148. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  149. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  150. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  151. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  152. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  153. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  154. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  155. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  156. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  157. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  158. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  159. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  160. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  161. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  162. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  163. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  164. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  165. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  166. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  167. data/lib/splitclient-rb/utilitites.rb +8 -0
  168. data/lib/splitclient-rb/validators.rb +142 -38
  169. data/lib/splitclient-rb/version.rb +1 -1
  170. data/lib/splitclient-rb.rb +101 -16
  171. data/sonar-project.properties +6 -0
  172. data/splitclient-rb.gemspec +28 -23
  173. metadata +262 -82
  174. data/.travis.yml +0 -11
  175. data/Appraisals +0 -10
  176. data/Detailed-README.md +0 -588
  177. data/NEWS +0 -141
  178. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -127
  179. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -96
  180. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -21
  181. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -56
  182. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +0 -46
  183. data/lib/splitclient-rb/cache/stores/segment_store.rb +0 -81
  184. data/lib/splitclient-rb/cache/stores/split_store.rb +0 -102
  185. data/lib/splitclient-rb/clients/localhost_split_client.rb +0 -183
  186. data/lib/splitclient-rb/engine/api/faraday_adapter/patched_net_http_persistent.rb +0 -46
  187. data/lib/splitclient-rb/engine/api/metrics.rb +0 -60
  188. data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
  189. data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -81
  190. data/lib/splitclient-rb/localhost_split_factory.rb +0 -13
  191. data/lib/splitclient-rb/localhost_utils.rb +0 -59
  192. data/lib/splitclient-rb/managers/localhost_split_manager.rb +0 -60
@@ -1,80 +1,134 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  class SplitFactory
3
5
  ROOT_PROCESS_ID = Process.pid
6
+ SINGLETON_WARN = 'We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'
7
+ LOCALHOST_API_KEY = 'localhost'
8
+
4
9
  include SplitIoClient::Cache::Repositories
5
10
  include SplitIoClient::Cache::Stores
11
+ include SplitIoClient::Cache::Senders
12
+ include SplitIoClient::Cache::Fetchers
6
13
 
7
- attr_reader :adapter, :client, :manager
14
+ attr_reader :adapter, :client, :manager, :config
8
15
 
9
16
  def initialize(api_key, config_hash = {})
10
17
  at_exit do
11
18
  unless ENV['SPLITCLIENT_ENV'] == 'test'
12
19
  if (Process.pid == ROOT_PROCESS_ID)
13
- SplitIoClient.configuration.logger.info('Split SDK shutdown started...')
20
+ @config.logger.info('Split SDK shutdown started...')
14
21
  @client.destroy if @client
15
22
  stop!
16
- SplitIoClient.configuration.logger.info('Split SDK shutdown complete')
23
+ @config.logger.info('Split SDK shutdown complete')
17
24
  end
18
25
  end
19
26
  end
20
27
 
21
28
  @api_key = api_key
22
- SplitIoClient.configure(config_hash)
23
29
 
24
- raise 'Invalid SDK mode' unless valid_mode
30
+ store_flag_sets = config_hash.key?(:flag_sets_filter) ? config_hash[:flag_sets_filter] : []
31
+ store_flag_sets = [] if !store_flag_sets.is_a?(Array)
32
+ flag_sets_count = 0
33
+ flag_sets_invalid = 0
25
34
 
26
- @cache_adapter = SplitIoClient.configuration.cache_adapter
35
+ @config = SplitConfig.new(config_hash.merge(localhost_mode: @api_key == LOCALHOST_API_KEY ))
27
36
 
28
- @splits_repository = SplitsRepository.new(@cache_adapter)
29
- @segments_repository = SegmentsRepository.new(@cache_adapter)
30
- @impressions_repository = ImpressionsRepository.new(SplitIoClient.configuration.impressions_adapter)
31
- @metrics_repository = MetricsRepository.new(SplitIoClient.configuration.metrics_adapter)
32
- @events_repository = EventsRepository.new(SplitIoClient.configuration.events_adapter)
33
-
34
- if SplitIoClient.configuration.mode == :standalone && SplitIoClient.configuration.block_until_ready > 0
35
- @sdk_blocker = SDKBlocker.new(@splits_repository, @segments_repository)
37
+ if config_hash.key?(:flag_sets_filter)
38
+ flag_sets_count = store_flag_sets.length()
39
+ flag_sets_invalid = flag_sets_count - @config.flag_sets_filter.length()
36
40
  end
37
41
 
38
- @adapter = start!
39
-
40
- @client = SplitClient.new(@api_key, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository)
41
- @manager = SplitManager.new(@api_key, @adapter, @splits_repository)
42
+ raise 'Invalid SDK mode' unless valid_mode
42
43
 
43
44
  validate_api_key
44
45
 
45
- @sdk_blocker.block if @sdk_blocker
46
+ register_factory
47
+
48
+ build_events_manager
49
+ build_telemetry_components
50
+ build_flag_sets_filter
51
+ build_repositories
52
+ build_telemetry_synchronizer(flag_sets_count, flag_sets_invalid)
53
+ build_impressions_sender_adapter
54
+ build_unique_keys_tracker
55
+ build_impressions_components
56
+
57
+ @status_manager = Engine::StatusManager.new(@config, @internal_events_queue)
58
+ @split_validator = SplitIoClient::Validators.new(@config)
59
+ @evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @rule_based_segment_repository, @config)
60
+
61
+ start!
62
+ fallback_treatment_calculator = SplitIoClient::Engine::FallbackTreatmentCalculator.new(@config.fallback_treatments_configuration)
63
+ @client = SplitClient.new(@api_key, repositories, @status_manager, @config, @impressions_manager, @evaluation_producer, @evaluator, @split_validator, fallback_treatment_calculator, @events_manager)
64
+ @manager = SplitManager.new(@splits_repository, @status_manager, @config)
46
65
  end
47
66
 
48
67
  def start!
49
- SplitAdapter.new(@api_key, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker)
68
+ return start_localhost_components if @config.localhost_mode
69
+
70
+ if @config.consumer?
71
+ build_synchronizer
72
+ build_sync_manager
73
+
74
+ @sync_manager.start_consumer
75
+ return
76
+ end
77
+
78
+ build_fetchers
79
+ build_synchronizer
80
+ build_streaming_components
81
+ build_sync_manager
82
+
83
+ @sync_manager.start
50
84
  end
51
85
 
52
86
  def stop!
53
- SplitIoClient.configuration.threads.each { |_, t| t.exit }
87
+ @config.threads.each { |_, t| t.exit }
88
+ end
89
+
90
+ def register_factory
91
+ SplitIoClient.load_factory_registry
92
+
93
+ number_of_factories = SplitIoClient.split_factory_registry.number_of_factories_for(@api_key)
94
+
95
+ if(number_of_factories > 0)
96
+ @config.logger.warn("Factory instantiation: You already have #{number_of_factories} factories with this API Key. #{SINGLETON_WARN}")
97
+ elsif(SplitIoClient.split_factory_registry.other_factories)
98
+ @config.logger.warn('Factory instantiation: You already have an instance of the Split factory.' \
99
+ " Make sure you definitely want this additional instance. #{SINGLETON_WARN}")
100
+ end
101
+
102
+ SplitIoClient.split_factory_registry.add(@api_key)
54
103
  end
55
104
 
56
105
  def valid_mode
57
106
  valid_startup_mode = false
58
- case SplitIoClient.configuration.mode
107
+ case @config.mode
59
108
  when :consumer
60
- if SplitIoClient.configuration.cache_adapter.is_a? SplitIoClient::Cache::Adapters::RedisAdapter
61
- valid_startup_mode = true
109
+ if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::RedisAdapter
110
+ if !@config.localhost_mode
111
+ valid_startup_mode = true
112
+ else
113
+ @config.logger.error('Localhost mode cannot be used with Redis. ' \
114
+ 'Use standalone mode and Memory adapter instead.')
115
+ end
62
116
  else
63
- SplitIoClient.configuration.logger.error('Consumer mode cannot be used with Memory adapter. ' \
117
+ @config.logger.error('Consumer mode cannot be used with Memory adapter. ' \
64
118
  'Use Redis adapter instead.')
65
119
  end
66
120
  when :standalone
67
- if SplitIoClient.configuration.cache_adapter.is_a? SplitIoClient::Cache::Adapters::MemoryAdapter
121
+ if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::MemoryAdapter
68
122
  valid_startup_mode = true
69
123
  else
70
- SplitIoClient.configuration.logger.error('Standalone mode cannot be used with Redis adapter. ' \
124
+ @config.logger.error('Standalone mode cannot be used with Redis adapter. ' \
71
125
  'Use Memory adapter instead.')
72
126
  end
73
127
  when :producer
74
- SplitIoClient.configuration.logger.error('Producer mode is no longer supported. Use Split Synchronizer. ' \
128
+ @config.logger.error('Producer mode is no longer supported. Use Split Synchronizer. ' \
75
129
  'See: https://github.com/splitio/split-synchronizer')
76
130
  else
77
- SplitIoClient.configuration.logger.error('Invalid SDK mode selected. ' \
131
+ @config.logger.error('Invalid SDK mode selected. ' \
78
132
  "Valid modes are 'standalone with memory adapter' and 'consumer with redis adapter'")
79
133
  end
80
134
 
@@ -87,12 +141,144 @@ module SplitIoClient
87
141
 
88
142
  def validate_api_key
89
143
  if(@api_key.nil?)
90
- SplitIoClient.configuration.logger.error('Factory Instantiation: you passed a nil api_key, api_key must be a non-empty String')
91
- SplitIoClient.configuration.valid_mode = false
144
+ @config.logger.error('Factory Instantiation: you passed a nil api_key, api_key must be a non-empty String')
145
+ @config.valid_mode = false
92
146
  elsif (@api_key.empty?)
93
- SplitIoClient.configuration.logger.error('Factory Instantiation: you passed and empty api_key, api_key must be a non-empty String')
94
- SplitIoClient.configuration.valid_mode = false
147
+ @config.logger.error('Factory Instantiation: you passed and empty api_key, api_key must be a non-empty String')
148
+ @config.valid_mode = false
149
+ end
150
+ end
151
+
152
+ def repositories
153
+ {
154
+ splits: @splits_repository,
155
+ segments: @segments_repository,
156
+ impressions: @impressions_repository,
157
+ events: @events_repository,
158
+ rule_based_segments: @rule_based_segment_repository
159
+ }
160
+ end
161
+
162
+ def start_localhost_components
163
+ LocalhostSplitStore.new(@splits_repository, @config, @status_manager).call
164
+
165
+ # Starts thread which loops constantly and cleans up repositories to avoid memory issues in localhost mode
166
+ LocalhostRepoCleaner.new(@impressions_repository, @events_repository, @config).call
167
+ end
168
+
169
+ def build_telemetry_components
170
+ @evaluation_consumer = Telemetry::EvaluationConsumer.new(@config)
171
+ @evaluation_producer = Telemetry::EvaluationProducer.new(@config)
172
+
173
+ @init_consumer = Telemetry::InitConsumer.new(@config)
174
+ @init_producer = Telemetry::InitProducer.new(@config)
175
+
176
+ @runtime_consumer = Telemetry::RuntimeConsumer.new(@config)
177
+ @runtime_producer = Telemetry::RuntimeProducer.new(@config)
178
+
179
+ @telemetry_consumers = { init: @init_consumer, evaluation: @evaluation_consumer, runtime: @runtime_consumer }
180
+ end
181
+
182
+ def build_fetchers
183
+ @split_fetcher = SplitFetcher.new(@splits_repository, @rule_based_segment_repository, @api_key, @config, @runtime_producer)
184
+ @segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @config, @runtime_producer)
185
+ end
186
+
187
+ def build_synchronizer
188
+ params = {
189
+ split_fetcher: @split_fetcher,
190
+ segment_fetcher: @segment_fetcher,
191
+ imp_counter: @impression_counter,
192
+ telemetry_synchronizer: @telemetry_synchronizer,
193
+ impressions_sender_adapter: @impressions_sender_adapter,
194
+ impressions_api: @impressions_api,
195
+ unique_keys_tracker: @unique_keys_tracker
196
+ }
197
+
198
+ @synchronizer = Engine::Synchronizer.new(repositories, @config, params)
199
+ end
200
+
201
+ def build_streaming_components
202
+ @push_status_queue = Queue.new
203
+ splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher, @rule_based_segment_repository)
204
+ segments_worker = SSE::Workers::SegmentsWorker.new(@synchronizer, @config, @segments_repository)
205
+ notification_manager_keeper = SSE::NotificationManagerKeeper.new(@config, @runtime_producer, @push_status_queue)
206
+ notification_processor = SSE::NotificationProcessor.new(@config, splits_worker, segments_worker)
207
+ event_parser = SSE::EventSource::EventParser.new(config)
208
+ sse_client = SSE::EventSource::Client.new(@config, @api_key, @runtime_producer, event_parser, notification_manager_keeper, notification_processor, @push_status_queue)
209
+ @sse_handler = SSE::SSEHandler.new(@config, splits_worker, segments_worker, sse_client)
210
+ @push_manager = Engine::PushManager.new(@config, @sse_handler, @api_key, @runtime_producer)
211
+ end
212
+
213
+ def build_sync_manager
214
+ @sync_manager = Engine::SyncManager.new(@config, @synchronizer, @runtime_producer, @telemetry_synchronizer, @status_manager, @sse_handler, @push_manager, @push_status_queue)
215
+ end
216
+
217
+ def build_repositories
218
+ if @config.cache_adapter.is_a? SplitIoClient::Cache::Adapters::RedisAdapter
219
+ @flag_sets_repository = SplitIoClient::Cache::Repositories::RedisFlagSetsRepository.new(@config)
220
+ else
221
+ @flag_sets_repository = SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new(@config.flag_sets_filter)
95
222
  end
223
+ @splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter, @internal_events_queue)
224
+ @segments_repository = SegmentsRepository.new(@config, @internal_events_queue)
225
+ @rule_based_segment_repository = RuleBasedSegmentsRepository.new(@config, @internal_events_queue)
226
+ @impressions_repository = ImpressionsRepository.new(@config)
227
+ @events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
228
+ end
229
+
230
+ def build_telemetry_synchronizer(flag_sets, flag_sets_invalid)
231
+ @telemetry_api = Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
232
+ @telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, @telemetry_api, flag_sets, flag_sets_invalid)
233
+ end
234
+
235
+ def build_unique_keys_tracker
236
+ bf = Cache::Filter::BloomFilter.new(30_000_000)
237
+ filter_adapter = Cache::Filter::FilterAdapter.new(@config, bf)
238
+ cache = Concurrent::Hash.new
239
+ @unique_keys_tracker = Engine::Impressions::UniqueKeysTracker.new(@config, filter_adapter, @impressions_sender_adapter, cache)
240
+ end
241
+
242
+ def build_impressions_observer
243
+ if (@config.cache_adapter == :redis && @config.impressions_mode != :optimized)
244
+ @impression_observer = Observers::NoopImpressionObserver.new
245
+ else
246
+ @impression_observer = Observers::ImpressionObserver.new
247
+ end
248
+ end
249
+
250
+ def build_impression_counter
251
+ @impression_counter = Engine::Common::ImpressionCounter.new
252
+ end
253
+
254
+ def build_impressions_sender_adapter
255
+ @impressions_api = Api::Impressions.new(@api_key, @config, @runtime_producer)
256
+ @impressions_sender_adapter = Cache::Senders::ImpressionsSenderAdapter.new(@config, @telemetry_api, @impressions_api)
257
+ end
258
+
259
+ def build_impressions_components
260
+ build_impressions_observer
261
+ build_impression_counter
262
+
263
+ @impressions_manager = Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter, @runtime_producer, @impression_observer, @unique_keys_tracker)
264
+ end
265
+
266
+ def build_flag_sets_filter
267
+ @flag_sets_filter = SplitIoClient::Cache::Filter::FlagSetsFilter.new(@config.flag_sets_filter)
268
+ end
269
+
270
+ def build_events_manager
271
+ @events_manager = Engine::Events::EventsManager.new(Engine::Events::EventsManagerConfig.new,
272
+ Engine::Events::EventsDelivery.new(@config),
273
+ @config)
274
+ if @config.consumer?
275
+ @internal_events_queue = Engine::Events::NoOpEventsQueue.new
276
+ return
277
+ end
278
+
279
+ @internal_events_queue = Queue.new
280
+ @events_task = Engine::Events::EventsTask.new(@events_manager.method(:notify_internal_event), @internal_events_queue, @config)
281
+ @events_task.start
96
282
  end
97
283
  end
98
284
  end
@@ -1,28 +1,7 @@
1
- require 'logger'
2
-
3
1
  module SplitIoClient
4
2
  class SplitFactoryBuilder
5
3
  def self.build(api_key, config = {})
6
- case api_key
7
- when 'localhost'
8
- SplitIoClient.configure( { logger: config[:logger] } )
9
-
10
- LocalhostSplitFactory.new(split_file(config[:split_file]), config[:reload_rate])
11
- else
12
- SplitFactory.new(api_key, config)
13
- end
14
- end
15
-
16
- private
17
-
18
- def self.split_file(split_file_path)
19
- return split_file_path unless split_file_path.nil?
20
-
21
- SplitIoClient.configuration.logger.warn('Localhost mode: .split mocks ' \
22
- 'will be deprecated soon in favor of YAML files, which provide more ' \
23
- 'targeting power. Take a look in our documentation.')
24
-
25
- File.join(Dir.home, '.split')
4
+ SplitFactory.new(api_key, config)
26
5
  end
27
6
  end
28
7
  end
@@ -0,0 +1,63 @@
1
+ require 'logger'
2
+ require 'socket'
3
+
4
+ module SplitIoClient
5
+
6
+ class << self
7
+ attr_accessor :split_factory_registry
8
+ end
9
+
10
+ def self.load_factory_registry
11
+ self.split_factory_registry ||= SplitFactoryRegistry.new
12
+ end
13
+
14
+ #
15
+ # This class manages configuration options for the split client library.
16
+ # If not custom configuration is required the default configuration values will be used
17
+ #
18
+ class SplitFactoryRegistry
19
+
20
+ attr_accessor :api_keys_hash
21
+
22
+ def initialize
23
+ @api_keys_hash = Hash.new
24
+ end
25
+
26
+ def add(api_key)
27
+ return unless api_key
28
+
29
+ @api_keys_hash[api_key] = 0 unless @api_keys_hash[api_key]
30
+ @api_keys_hash[api_key] += 1
31
+ end
32
+
33
+ def remove(api_key)
34
+ return unless api_key
35
+
36
+ @api_keys_hash[api_key] -= 1 if @api_keys_hash[api_key]
37
+ @api_keys_hash.delete(api_key) if @api_keys_hash[api_key] == 0
38
+ end
39
+
40
+ def number_of_factories_for(api_key)
41
+ return 0 unless api_key
42
+ return 0 unless @api_keys_hash.key?(api_key)
43
+
44
+ @api_keys_hash[api_key]
45
+ end
46
+
47
+ def other_factories
48
+ return !@api_keys_hash.empty?
49
+ end
50
+
51
+ def active_factories
52
+ @api_keys_hash.length
53
+ end
54
+
55
+ def redundant_active_factories
56
+ to_return = 0
57
+
58
+ @api_keys_hash.each { |key| to_return += (key[1]-1) }
59
+
60
+ to_return
61
+ end
62
+ end
63
+ end
@@ -1,24 +1,23 @@
1
- require 'singleton'
2
-
3
1
  module SplitIoClient
4
2
  class SplitLogger
5
- include Singleton
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
6
 
7
7
  def log_if_debug(message)
8
- SplitIoClient.configuration.logger.debug(message) if SplitIoClient.configuration.debug_enabled
8
+ @config.logger.debug(message) if @config.debug_enabled
9
9
  end
10
10
 
11
11
  def log_if_transport(message)
12
- SplitIoClient.configuration.logger.debug(message) if SplitIoClient.configuration.transport_debug_enabled
12
+ @config.logger.debug(message) if @config.transport_debug_enabled
13
13
  end
14
14
 
15
- def log_error(message)
16
- SplitIoClient.configuration.logger.error(message)
15
+ def error(message)
16
+ @config.logger.error(message)
17
17
  end
18
18
 
19
- class << self
20
- extend Forwardable
21
- def_delegators :instance, *SplitLogger.instance_methods(false)
19
+ def debug(message)
20
+ @config.logger.debug(message) if @config.debug_enabled
22
21
  end
23
22
  end
24
23
  end