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,126 +1,198 @@
1
1
  module SplitIoClient
2
+ EVENTS_SIZE_THRESHOLD = 32768
3
+ EVENT_AVERAGE_SIZE = 1024
4
+ GET_TREATMENT = 'get_treatment'
5
+ GET_TREATMENTS = 'get_treatments'
6
+ GET_TREATMENT_WITH_CONFIG = 'get_treatment_with_config'
7
+ GET_TREATMENTS_WITH_CONFIG = 'get_treatments_with_config'
8
+ GET_TREATMENTS_BY_FLAG_SET = 'get_treatments_by_flag_set'
9
+ GET_TREATMENTS_BY_FLAG_SETS = 'get_treatments_by_flag_sets'
10
+ GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET = 'get_treatments_with_config_by_flag_set'
11
+ GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = 'get_treatments_with_config_by_flag_sets'
12
+ TRACK = 'track'
2
13
 
3
14
  class SplitClient
4
15
  #
5
16
  # Creates a new split client instance that connects to split.io API.
6
17
  #
7
- # @param api_key [String] the API key for your split account
18
+ # @param sdk_key [String] the SDK key for your split account
8
19
  #
9
20
  # @return [SplitIoClient] split.io client instance
10
- def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository)
11
- @splits_repository = splits_repository
12
- @segments_repository = segments_repository
13
- @impressions_repository = impressions_repository
14
- @metrics_repository = metrics_repository
15
- @events_repository = events_repository
21
+ def initialize(sdk_key, repositories, status_manager, config, impressions_manager, telemetry_evaluation_producer, evaluator, split_validator, fallback_treatment_calculator, events_manager)
22
+ @api_key = sdk_key
23
+ @splits_repository = repositories[:splits]
24
+ @segments_repository = repositories[:segments]
25
+ @rule_based_segments_repository = repositories[:rule_based_segments]
26
+ @impressions_repository = repositories[:impressions]
27
+ @events_repository = repositories[:events]
28
+ @status_manager = status_manager
16
29
  @destroyed = false
17
-
18
- @adapter = adapter
30
+ @config = config
31
+ @impressions_manager = impressions_manager
32
+ @telemetry_evaluation_producer = telemetry_evaluation_producer
33
+ @split_validator = split_validator
34
+ @evaluator = evaluator
35
+ @fallback_treatment_calculator = fallback_treatment_calculator
36
+ @events_manager = events_manager
19
37
  end
20
38
 
21
39
  def get_treatment(
22
- key, split_name, attributes = {}, split_data = nil, store_impressions = true,
40
+ key, split_name, attributes = {}, evaluation_options = nil, split_data = nil, store_impressions = nil,
23
41
  multiple = false, evaluator = nil
24
42
  )
25
- treatment = treatment(key, split_name, attributes, split_data, store_impressions, multiple, evaluator)
26
- if multiple
27
- treatment.tap { |t| t.delete(:config) }
28
- else
29
- treatment[:treatment]
30
- end
43
+ log_deprecated_warning(GET_TREATMENT, evaluator, 'evaluator')
44
+
45
+ result = treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT, multiple, evaluation_options)
46
+ return result.tap { |t| t.delete(:config) } if multiple
47
+ result[:treatment]
31
48
  end
32
49
 
33
50
  def get_treatment_with_config(
34
- key, split_name, attributes = {}, split_data = nil, store_impressions = true,
51
+ key, split_name, attributes = {}, evaluation_options = nil, split_data = nil, store_impressions = nil,
35
52
  multiple = false, evaluator = nil
36
53
  )
37
- treatment(key, split_name, attributes, split_data, store_impressions, multiple, evaluator, 'get_treatment_with_config')
54
+ log_deprecated_warning(GET_TREATMENT, evaluator, 'evaluator')
55
+ result = treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT_WITH_CONFIG, multiple, evaluation_options)
56
+
57
+ { :config => result[:config], :treatment => result[:treatment] }
38
58
  end
39
59
 
40
- def get_treatments(key, split_names, attributes = {})
41
- treatments = treatments(key, split_names, attributes)
60
+ def get_treatments(key, split_names, attributes = {}, evaluation_options = nil)
61
+ treatments = treatments(key, split_names, attributes, evaluation_options)
62
+
42
63
  return treatments if treatments.nil?
43
64
  keys = treatments.keys
44
65
  treats = treatments.map { |_,t| t[:treatment] }
45
66
  Hash[keys.zip(treats)]
46
67
  end
47
68
 
48
- def get_treatments_with_config(key, split_names, attributes = {})
49
- treatments(key, split_names, attributes,'get_treatments_with_config')
69
+ def get_treatments_with_config(key, split_names, attributes = {}, evaluation_options = nil)
70
+ results = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG)
71
+
72
+ results.map{|key, value|
73
+ [key, { treatment: value[:treatment], config: value[:config] }]
74
+ }.to_h
50
75
  end
51
76
 
52
- def destroy
53
- SplitIoClient.configuration.logger.info('Split client shutdown started...') if SplitIoClient.configuration.debug_enabled
77
+ def get_treatments_by_flag_set(key, flag_set, attributes = {}, evaluation_options = nil)
78
+ valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_BY_FLAG_SET, [flag_set])
79
+ split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
80
+ treatments = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_BY_FLAG_SET)
81
+ return treatments if treatments.nil?
82
+ keys = treatments.keys
83
+ treats = treatments.map { |_,t| t[:treatment] }
84
+ Hash[keys.zip(treats)]
85
+ end
86
+
87
+ def get_treatments_by_flag_sets(key, flag_sets, attributes = {}, evaluation_options = nil)
88
+ valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_BY_FLAG_SETS, flag_sets)
89
+ split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
90
+ treatments = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_BY_FLAG_SETS)
91
+ return treatments if treatments.nil?
92
+ keys = treatments.keys
93
+ treats = treatments.map { |_,t| t[:treatment] }
94
+ Hash[keys.zip(treats)]
95
+ end
96
+
97
+ def get_treatments_with_config_by_flag_set(key, flag_set, attributes = {}, evaluation_options = nil)
98
+ valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, [flag_set])
99
+ split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
100
+ results = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET)
101
+
102
+ results.map{|key, value|
103
+ [key, { treatment: value[:treatment], config: value[:config] }]
104
+ }.to_h
105
+ end
106
+
107
+ def get_treatments_with_config_by_flag_sets(key, flag_sets, attributes = {}, evaluation_options = nil)
108
+ valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, flag_sets)
109
+ split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
110
+ results = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS)
111
+
112
+ results.map{|key, value|
113
+ [key, { treatment: value[:treatment], config: value[:config] }]
114
+ }.to_h
115
+ end
54
116
 
55
- SplitIoClient.configuration.threads.select { |name, thread| name.to_s.end_with? 'sender' }.values.each do |thread|
117
+ def destroy
118
+ @config.logger.info('Split client shutdown started...') if @config.debug_enabled
119
+ if !@config.cache_adapter.is_a?(SplitIoClient::Cache::Adapters::RedisAdapter) && @config.impressions_mode != :none &&
120
+ (!@impressions_repository.empty? || !@events_repository.empty?)
121
+ @config.logger.debug("Impressions and/or Events cache is not empty") if @config.debug_enabled
122
+ # Adding small delay to ensure sender threads are fully running
123
+ sleep(0.1)
124
+ if !@config.threads.key?(:impressions_sender) || !@config.threads.key?(:events_sender)
125
+ @config.logger.debug("Periodic data recording thread has not started yet, waiting for service startup.") if @config.debug_enabled
126
+ @config.threads[:start_sdk].join(5) if @config.threads.key?(:start_sdk)
127
+ end
128
+ end
129
+ @config.threads.select { |name, thread| name.to_s.end_with? 'sender' }.values.each do |thread|
56
130
  thread.raise(SplitIoClient::SDKShutdownException)
57
131
  thread.join
58
132
  end
59
133
 
60
- SplitIoClient.configuration.threads.values.each { |thread| Thread.kill(thread) }
134
+ @config.threads.values.each { |thread| Thread.kill(thread) }
61
135
 
62
136
  @splits_repository.clear
63
137
  @segments_repository.clear
138
+ @rule_based_segments_repository.clear
139
+
140
+ SplitIoClient.load_factory_registry
141
+ SplitIoClient.split_factory_registry.remove(@api_key)
64
142
 
65
- SplitIoClient.configuration.logger.info('Split client shutdown complete') if SplitIoClient.configuration.debug_enabled
66
- SplitIoClient.configuration.valid_mode = false
143
+ @config.logger.info('Split client shutdown complete') if @config.debug_enabled
144
+ @config.valid_mode = false
67
145
  @destroyed = true
68
146
  end
69
147
 
70
- def store_impression(split_name, matching_key, bucketing_key, treatment, store_impressions, attributes)
71
- time = (Time.now.to_f * 1000.0).to_i
148
+ def track(key, traffic_type_name, event_type, value = nil, properties = nil)
149
+ return false unless valid_client && @config.split_validator.valid_track_parameters(key, traffic_type_name, event_type, value, properties)
150
+
151
+ start = Time.now
152
+ properties_size = EVENT_AVERAGE_SIZE
72
153
 
73
- return if SplitIoClient.configuration.disable_impressions || !store_impressions
154
+ if !properties.nil?
155
+ properties, size = validate_properties(properties)
156
+ properties_size += size
157
+ return false unless check_properties_size(properties_size)
158
+ end
74
159
 
75
- @impressions_repository.add(
76
- matching_key,
77
- bucketing_key,
78
- split_name,
79
- treatment,
80
- time
81
- )
160
+ if ready? && !@config.localhost_mode && !@splits_repository.traffic_type_exists(traffic_type_name)
161
+ @config.logger.warn("track: Traffic Type #{traffic_type_name} " \
162
+ "does not have any corresponding feature flags in this environment, make sure you're tracking " \
163
+ 'your events to a valid traffic type defined in the Split user interface')
164
+ end
82
165
 
83
- route_impression(split_name, matching_key, bucketing_key, time, treatment, attributes)
166
+ @events_repository.add(key.to_s, traffic_type_name.downcase, event_type.to_s, (Time.now.to_f * 1000).to_i, value, properties, properties_size)
167
+ record_latency(TRACK, start)
168
+ true
169
+ rescue StandardError => e
170
+ @config.log_found_exception(__method__.to_s, e)
171
+ record_exception(TRACK)
84
172
 
85
- rescue StandardError => error
86
- SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
173
+ false
87
174
  end
88
175
 
89
- def route_impression(split_name, matching_key, bucketing_key, time, treatment, attributes)
90
- impression_router.add(
91
- split_name: split_name,
92
- matching_key: matching_key,
93
- bucketing_key: bucketing_key,
94
- time: time,
95
- treatment: treatment,
96
- attributes: attributes
97
- )
176
+ def block_until_ready(time = nil)
177
+ @status_manager.wait_until_ready(time) if @status_manager
98
178
  end
99
179
 
100
- def route_impressions(split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
101
- impression_router.add_bulk(
102
- split_names: split_names,
103
- matching_key: matching_key,
104
- bucketing_key: bucketing_key,
105
- time: time,
106
- treatments_labels_change_numbers: treatments_labels_change_numbers,
107
- attributes: attributes
108
- )
180
+ def register(sdk_event, handler)
181
+ @events_manager.register(sdk_event, handler)
109
182
  end
110
183
 
111
- def impression_router
112
- @impression_router ||= SplitIoClient::ImpressionRouter.new
184
+ def unregister(sdk_event, handler)
185
+ @events_manager.unregister(sdk_event)
113
186
  end
114
187
 
115
- def track(key, traffic_type_name, event_type, value = nil)
116
- return false unless valid_client && SplitIoClient::Validators.valid_track_parameters(key, traffic_type_name, event_type, value)
117
- begin
118
- @events_repository.add(key.to_s, traffic_type_name.downcase, event_type.to_s, (Time.now.to_f * 1000).to_i, value)
119
- true
120
- rescue StandardError => error
121
- SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
122
- false
188
+ private
189
+
190
+ def check_properties_size(properties_size, msg = "Event not queued")
191
+ if (properties_size > EVENTS_SIZE_THRESHOLD)
192
+ @config.logger.error("The maximum size allowed for the properties is #{EVENTS_SIZE_THRESHOLD}. Current is #{properties_size}. #{msg}")
193
+ return false
123
194
  end
195
+ return true
124
196
  end
125
197
 
126
198
  def keys_from_key(key)
@@ -132,7 +204,7 @@ module SplitIoClient
132
204
  end
133
205
  end
134
206
 
135
- def parsed_treatment(multiple, treatment_data)
207
+ def parsed_treatment(treatment_data, multiple = false)
136
208
  if multiple
137
209
  {
138
210
  treatment: treatment_data[:treatment],
@@ -141,78 +213,141 @@ module SplitIoClient
141
213
  config: treatment_data[:config]
142
214
  }
143
215
  else
144
- {
145
- treatment: treatment_data[:treatment],
146
- config: treatment_data[:config]
147
- }
216
+ {
217
+ treatment: treatment_data[:treatment],
218
+ config: treatment_data[:config],
219
+ }
148
220
  end
149
221
  end
150
222
 
151
223
  def sanitize_split_names(calling_method, split_names)
224
+ return nil if !split_names.is_a?(Array)
225
+
152
226
  split_names.compact.uniq.select do |split_name|
153
- if (split_name.is_a?(String) || split_name.is_a?(Symbol)) && !split_name.empty?
227
+ if split_name.nil?
228
+ false
229
+ elsif (split_name.is_a?(String) || split_name.is_a?(Symbol)) && !split_name.empty?
154
230
  true
155
231
  elsif split_name.is_a?(String) && split_name.empty?
156
- SplitIoClient.configuration.logger.warn("#{calling_method}: you passed an empty split_name, split_name must be a non-empty String or a Symbol")
232
+ @config.logger.warn("#{calling_method}: you passed an empty feature_flag_name, flag name must be a non-empty String or a Symbol")
157
233
  false
158
234
  else
159
- SplitIoClient.configuration.logger.warn("#{calling_method}: you passed an invalid split_name, split_name must be a non-empty String or a Symbol")
235
+ @config.logger.warn("#{calling_method}: you passed an invalid feature_flag_name, flag name must be a non-empty String or a Symbol")
160
236
  false
161
237
  end
162
238
  end
163
239
  end
164
240
 
165
- private
241
+ def validate_properties(properties, method = 'Event')
242
+ properties_count = 0
243
+ size = 0
244
+
245
+ fixed_properties = properties.each_with_object({}) { |(key, value), result|
246
+
247
+ if(key.is_a?(String) || key.is_a?(Symbol))
248
+ properties_count += 1
249
+ size += variable_size(key)
250
+ if value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.nil?
251
+ result[key] = value
252
+ size += variable_size(value)
253
+ else
254
+ @config.logger.warn("Property #{key} is of invalid type. Setting value to nil")
255
+ result[key] = nil
256
+ end
257
+ end
258
+ }
259
+
260
+ @config.logger.warn("#{method} has more than 300 properties. Some of them will be trimmed when processed") if properties_count > 300
261
+
262
+ return fixed_properties, size
263
+ end
264
+
265
+ def validate_evaluation_options(evaluation_options)
266
+ if !evaluation_options.is_a?(SplitIoClient::Engine::Models::EvaluationOptions)
267
+ @config.logger.warn("Option #{evaluation_options} should be a EvaluationOptions type. Setting value to nil")
268
+ return nil, 0
269
+ end
270
+ evaluation_options.properties = evaluation_options.properties.transform_keys(&:to_sym)
271
+ evaluation_options.properties, size = validate_properties(evaluation_options.properties, 'Treatment')
272
+ return evaluation_options, size
273
+ end
166
274
 
167
275
  def valid_client
168
276
  if @destroyed
169
- SplitIoClient.configuration.logger.error('Client has already been destroyed - no calls possible')
277
+ @config.logger.error('Client has already been destroyed - no calls possible')
170
278
  return false
171
279
  end
172
- SplitIoClient.configuration.valid_mode
280
+ @config.valid_mode
173
281
  end
174
282
 
175
- def treatments(key, split_names, attributes = {}, calling_method = 'get_treatments')
176
- return nil unless SplitIoClient::Validators.valid_get_treatments_parameters(calling_method, split_names)
283
+ def treatments(key, feature_flag_names, attributes = {}, evaluation_options = nil, calling_method = 'get_treatments')
284
+ sanitized_feature_flag_names = sanitize_split_names(calling_method, feature_flag_names)
177
285
 
178
- sanitized_split_names = sanitize_split_names(calling_method, split_names)
286
+ if sanitized_feature_flag_names.nil?
287
+ @config.logger.error("#{calling_method}: feature_flag_names must be a non-empty Array")
288
+ return nil
289
+ end
179
290
 
180
- if sanitized_split_names.empty?
181
- SplitIoClient.configuration.logger.error("#{calling_method}: split_names must be a non-empty Array")
291
+ if sanitized_feature_flag_names.empty?
292
+ @config.logger.error("#{calling_method}: feature_flag_names must be a non-empty Array")
182
293
  return {}
183
294
  end
184
295
 
185
296
  bucketing_key, matching_key = keys_from_key(key)
186
297
  bucketing_key = bucketing_key ? bucketing_key.to_s : nil
187
298
  matching_key = matching_key ? matching_key.to_s : nil
299
+ attributes = parsed_attributes(attributes)
188
300
 
189
- evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, true)
190
- start = Time.now
191
- treatments_labels_change_numbers =
192
- @splits_repository.get_splits(sanitized_split_names).each_with_object({}) do |(name, data), memo|
193
- memo.merge!(name => treatment(key, name, attributes, data, false, true, evaluator))
194
- end
195
- latency = (Time.now - start) * 1000.0
196
- # Measure
197
- @adapter.metrics.time('sdk.' + calling_method, latency)
301
+ if !@config.split_validator.valid_get_treatments_parameters(calling_method, key, sanitized_feature_flag_names, matching_key, bucketing_key, attributes)
302
+ to_return = Hash.new
303
+ sanitized_feature_flag_names.each {|name|
304
+ to_return[name.to_sym] = check_fallback_treatment(name, '')
305
+ }
306
+ return to_return
307
+ end
198
308
 
199
- unless SplitIoClient.configuration.disable_impressions
200
- time = (Time.now.to_f * 1000.0).to_i
201
- @impressions_repository.add_bulk(
202
- matching_key, bucketing_key, treatments_labels_change_numbers, time
203
- )
309
+ if !ready?
310
+ impressions = []
311
+ to_return = Hash.new
312
+ sanitized_feature_flag_names.each {|name|
313
+ treatment_data = check_fallback_treatment(name, Engine::Models::Label::NOT_READY)
314
+ to_return[name.to_sym] = treatment_data
204
315
 
205
- route_impressions(sanitized_split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
316
+ impressions << { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, name.to_sym,
317
+ get_treatment_without_config(treatment_data), false, { attributes: attributes, time: nil },
318
+ evaluation_options), :disabled => false }
319
+ }
320
+ @impressions_manager.track(impressions)
321
+ return to_return
206
322
  end
207
323
 
208
- split_names_keys = treatments_labels_change_numbers.keys
209
- treatments = treatments_labels_change_numbers.values.map do |v|
324
+ valid_feature_flag_names = []
325
+ sanitized_feature_flag_names.each { |feature_flag_name|
326
+ valid_feature_flag_names << feature_flag_name unless feature_flag_name.nil?
327
+ }
328
+ start = Time.now
329
+
330
+ feature_flags = @splits_repository.splits(valid_feature_flag_names)
331
+ treatments = Hash.new
332
+ invalid_treatments = Hash.new
333
+ feature_flags.each do |key, feature_flag|
334
+ if feature_flag.nil?
335
+ @config.logger.warn("#{calling_method}: you passed #{key} that " \
336
+ 'does not exist in this environment, please double check what feature flags exist in the Split user interface')
337
+ invalid_treatments[key] = check_fallback_treatment(key, Engine::Models::Label::NOT_FOUND)
338
+ next
339
+ end
340
+ treatments_labels_change_numbers, impressions = evaluate_treatment(feature_flag, key, bucketing_key, matching_key, attributes, calling_method, false, evaluation_options)
341
+ treatments[key] =
210
342
  {
211
- treatment: v[:treatment],
212
- config: v[:config]
343
+ treatment: treatments_labels_change_numbers[:treatment],
344
+ config: treatments_labels_change_numbers[:config]
213
345
  }
346
+ @impressions_manager.track(impressions) unless impressions.empty?
214
347
  end
215
- Hash[split_names_keys.zip(treatments)]
348
+ record_latency(calling_method, start)
349
+
350
+ treatments.merge(invalid_treatments)
216
351
  end
217
352
 
218
353
  #
@@ -223,61 +358,173 @@ module SplitIoClient
223
358
  # @param attributes [Hash] attributes to pass to the treatment class
224
359
  # @param split_data [Hash] split data, when provided this method doesn't fetch splits_repository for the data
225
360
  # @param store_impressions [Boolean] impressions aren't stored if this flag is false
226
- # @param multiple [Hash] internal flag to signal if method is called by get_treatments
227
- # @param evaluator [Evaluator] Evaluator class instance, used to cache treatments
228
- #
229
361
  # @return [String/Hash] Treatment as String or Hash of treatments in case of array of features
230
- def treatment(
231
- key, split_name, attributes = {}, split_data = nil, store_impressions = true,
232
- multiple = false, evaluator = nil, calling_method = 'get_treatment'
233
- )
234
- control_treatment = { label: Engine::Models::Label::EXCEPTION, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL, config: nil }
235
- parsed_control_treatment = parsed_treatment(multiple, control_treatment)
362
+ def treatment(key, feature_flag_name, attributes = {}, split_data = nil, store_impressions = nil,
363
+ calling_method = 'get_treatment', multiple = false, evaluation_options = nil)
236
364
 
365
+ log_deprecated_warning(calling_method, split_data, 'split_data')
366
+ log_deprecated_warning(calling_method, store_impressions, 'store_impressions')
367
+
368
+ impressions = []
237
369
  bucketing_key, matching_key = keys_from_key(key)
238
370
 
239
- return parsed_control_treatment unless valid_client && SplitIoClient::Validators.valid_get_treatment_parameters(calling_method, key, split_name, matching_key, bucketing_key, attributes)
371
+ attributes = parsed_attributes(attributes)
372
+
373
+ return parsed_treatment(check_fallback_treatment(feature_flag_name, ""), multiple) unless valid_client && @config.split_validator.valid_get_treatment_parameters(calling_method, key, feature_flag_name, matching_key, bucketing_key, attributes)
240
374
 
241
375
  bucketing_key = bucketing_key ? bucketing_key.to_s : nil
242
376
  matching_key = matching_key.to_s
243
- sanitized_split_name = split_name.to_s.strip
377
+ sanitized_feature_flag_name = feature_flag_name.to_s.strip
244
378
 
245
- if split_name.to_s != sanitized_split_name
246
- SplitIoClient.configuration.logger.warn("#{calling_method}: split_name #{split_name} has extra whitespace, trimming")
247
- split_name = sanitized_split_name
379
+ if feature_flag_name.to_s != sanitized_feature_flag_name
380
+ @config.logger.warn("#{calling_method}: feature_flag_name #{feature_flag_name} has extra whitespace, trimming")
381
+ feature_flag_name = sanitized_feature_flag_name
248
382
  end
249
383
 
250
- evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
384
+ feature_flag = @splits_repository.get_split(feature_flag_name)
385
+ treatments, impressions_decorator = evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple, evaluation_options)
386
+
387
+ @impressions_manager.track(impressions_decorator) unless impressions_decorator.nil?
388
+ treatments
389
+ end
390
+
391
+ def log_deprecated_warning(calling_method, parameter, parameter_name)
392
+ @config.logger.warn("#{calling_method}: detected #{parameter_name} parameter used, this parameter is deprecated and its value is ignored.") unless parameter.nil?
393
+ end
251
394
 
395
+ def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple = false, evaluation_options = nil)
396
+ impressions_decorator = []
252
397
  begin
253
398
  start = Time.now
399
+ if feature_flag.nil? && ready?
400
+ @config.logger.warn("#{calling_method}: you passed #{feature_flag_name} that " \
401
+ 'does not exist in this environment, please double check what feature flags exist in the Split user interface')
402
+ return check_fallback_treatment(feature_flag_name, Engine::Models::Label::NOT_FOUND), nil
403
+ end
254
404
 
255
- split = multiple ? split_data : @splits_repository.get_split(split_name)
256
-
257
- if split.nil?
258
- SplitIoClient.configuration.logger.warn("split_name: #{split_name} does not exist. Returning CONTROL")
259
- return parsed_control_treatment
405
+ if !feature_flag.nil? && ready?
406
+ treatment_data = @evaluator.evaluate_feature_flag(
407
+ { bucketing_key: bucketing_key, matching_key: matching_key }, feature_flag, attributes
408
+ )
409
+ impressions_disabled = feature_flag[:impressionsDisabled]
410
+ else
411
+ @config.logger.error("#{calling_method}: the SDK is not ready, results may be incorrect for feature flag #{feature_flag_name}. Make sure to wait for SDK readiness before using this method.")
412
+ treatment_data = check_fallback_treatment(feature_flag_name, Engine::Models::Label::NOT_READY)
413
+ impressions_disabled = false
260
414
  end
261
415
 
262
- treatment_data =
263
- evaluator.call(
264
- { bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
265
- )
416
+ evaluation_options, size = validate_evaluation_options(evaluation_options) unless evaluation_options.nil?
417
+ evaluation_options.properties = nil unless evaluation_options.nil? or check_properties_size((EVENT_AVERAGE_SIZE + size), "Properties are ignored")
418
+
419
+ record_latency(calling_method, start)
420
+ impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, treatment_data, impressions_disabled, { attributes: attributes, time: nil }, evaluation_options), :disabled => impressions_disabled }
421
+ impressions_decorator << impression_decorator unless impression_decorator.nil?
422
+ rescue StandardError => e
423
+ @config.log_found_exception(__method__.to_s, e)
424
+ record_exception(calling_method)
425
+ treatment_data = check_fallback_treatment(feature_flag_name, Engine::Models::Label::EXCEPTION)
426
+ impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, get_treatment_without_config(treatment_data), false, { attributes: attributes, time: nil }, evaluation_options), :disabled => false }
427
+
428
+ impressions_decorator << impression_decorator unless impression_decorator.nil?
429
+
430
+ return parsed_treatment(treatment_data, multiple), impressions_decorator
431
+ end
432
+ return parsed_treatment(treatment_data, multiple), impressions_decorator
433
+ end
434
+
435
+ def variable_size(value)
436
+ value.is_a?(String) ? value.length : 0
437
+ end
438
+
439
+ def ready?
440
+ return @status_manager.ready? if @status_manager
441
+ true
442
+ end
443
+
444
+ def parsed_attributes(attributes)
445
+ return attributes || attributes.to_h
446
+ end
447
+
448
+ def record_latency(method, start)
449
+ bucket = BinarySearchLatencyTracker.get_bucket((Time.now - start) * 1000.0)
450
+
451
+ case method
452
+ when GET_TREATMENT
453
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENT, bucket)
454
+ when GET_TREATMENTS
455
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS, bucket)
456
+ when GET_TREATMENT_WITH_CONFIG
457
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENT_WITH_CONFIG, bucket)
458
+ when GET_TREATMENTS_WITH_CONFIG
459
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG, bucket)
460
+ when GET_TREATMENTS_BY_FLAG_SET
461
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SET, bucket)
462
+ when GET_TREATMENTS_BY_FLAG_SETS
463
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SETS, bucket)
464
+ when GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET
465
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET, bucket)
466
+ when GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
467
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, bucket)
468
+ when TRACK
469
+ @telemetry_evaluation_producer.record_latency(Telemetry::Domain::Constants::TRACK, bucket)
470
+ end
471
+ end
266
472
 
267
- latency = (Time.now - start) * 1000.0
268
- store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
473
+ def record_exception(method)
474
+ case method
475
+ when GET_TREATMENT
476
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENT)
477
+ when GET_TREATMENTS
478
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS)
479
+ when GET_TREATMENT_WITH_CONFIG
480
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENT_WITH_CONFIG)
481
+ when GET_TREATMENTS_WITH_CONFIG
482
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG)
483
+ when GET_TREATMENTS_BY_FLAG_SET
484
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SET)
485
+ when GET_TREATMENTS_BY_FLAG_SETS
486
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS_BY_FLAG_SETS)
487
+ when GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET
488
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SET)
489
+ when GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS
490
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TREATMENTS_WITH_CONFIG_BY_FLAG_SETS)
491
+ when TRACK
492
+ @telemetry_evaluation_producer.record_exception(Telemetry::Domain::Constants::TRACK)
493
+ end
494
+ end
269
495
 
270
- # Measure
271
- @adapter.metrics.time('sdk.' + calling_method, latency) unless multiple
272
- rescue StandardError => error
273
- SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
496
+ def check_fallback_treatment(feature_name, label)
497
+ return {
498
+ label: (label != '')? label : nil,
499
+ treatment: Engine::Models::Treatment::CONTROL,
500
+ config: nil,
501
+ change_number: nil
502
+ } unless feature_name.is_a?(Symbol) || feature_name.is_a?(String)
503
+
504
+ fallback_treatment = @fallback_treatment_calculator.resolve(feature_name.to_sym, label)
505
+
506
+ {
507
+ label: (label != '')? fallback_treatment.label : nil,
508
+ treatment: fallback_treatment.treatment,
509
+ config: get_fallback_config(fallback_treatment),
510
+ change_number: nil
511
+ }
512
+ end
274
513
 
275
- store_impression(split_name, matching_key, bucketing_key, control_treatment, store_impressions, attributes)
514
+ def get_treatment_without_config(treatment)
515
+ {
516
+ label: treatment[:label],
517
+ treatment: treatment[:treatment],
518
+ }
519
+ end
276
520
 
277
- return parsed_control_treatment
521
+ def get_fallback_config(fallback_treatment)
522
+ if fallback_treatment.config != nil
523
+ return fallback_treatment.config
278
524
  end
279
525
 
280
- parsed_treatment(multiple, treatment_data)
526
+ return nil
281
527
  end
528
+
282
529
  end
283
530
  end