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.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.github/pull_request_template.md +9 -0
- data/.github/workflows/ci.yml +90 -0
- data/.github/workflows/update-license-year.yml +45 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +76 -0
- data/.simplecov +1 -0
- data/CHANGES.txt +361 -2
- data/CONTRIBUTORS-GUIDE.md +49 -0
- data/Gemfile +2 -0
- data/LICENSE +3 -36
- data/NOTICE.txt +5 -0
- data/README.md +59 -127
- data/Rakefile +27 -3
- data/ext/murmurhash/MurmurHash3.java +302 -0
- data/gemfiles/faraday_after_0.13.gemfile +7 -0
- data/gemfiles/faraday_before_0.13.gemfile +8 -0
- data/lib/murmurhash/base.rb +58 -0
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/murmurhash/murmurhash_mri.rb +3 -0
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +130 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +137 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +53 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +178 -0
- data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
- data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
- data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
- data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
- data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
- data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
- data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +45 -0
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +35 -0
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +61 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +56 -0
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +57 -0
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +23 -0
- data/lib/splitclient-rb/cache/repositories/repository.rb +24 -0
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +124 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +296 -0
- data/lib/splitclient-rb/cache/routers/impression_router.rb +60 -0
- data/lib/splitclient-rb/cache/senders/events_sender.rb +42 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
- data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +95 -0
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +52 -0
- data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
- data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
- data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
- data/lib/splitclient-rb/clients/split_client.rb +530 -0
- data/lib/splitclient-rb/constants.rb +16 -0
- data/lib/splitclient-rb/engine/api/client.rb +87 -0
- data/lib/splitclient-rb/engine/api/events.rb +57 -0
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +58 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +79 -0
- data/lib/splitclient-rb/engine/api/segments.rb +78 -0
- data/lib/splitclient-rb/engine/api/splits.rb +139 -0
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
- data/lib/splitclient-rb/engine/auth_api_client.rb +100 -0
- data/lib/splitclient-rb/engine/back_off.rb +26 -0
- data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
- data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/evaluator/splitter.rb +35 -22
- data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
- data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
- data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
- data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
- data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
- data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
- data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
- data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/all_keys_matcher.rb +10 -21
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +47 -0
- data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/matchers/combiners.rb +4 -6
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +80 -0
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +20 -0
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +16 -0
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +43 -0
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +26 -0
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +42 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +37 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +44 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +16 -0
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +43 -0
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +43 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/matcher.rb +52 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +29 -0
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +47 -0
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +22 -0
- data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
- data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
- data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +27 -0
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +40 -0
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +66 -0
- data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
- data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
- data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
- data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
- data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
- data/lib/splitclient-rb/engine/models/label.rb +10 -0
- data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +16 -0
- data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/split.rb +17 -0
- data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
- data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
- data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +271 -0
- data/lib/splitclient-rb/engine/parser/evaluator.rb +112 -0
- data/lib/{splitclient-engine → splitclient-rb/engine}/parser/partition.rb +2 -4
- data/lib/splitclient-rb/engine/push_manager.rb +66 -0
- data/lib/splitclient-rb/engine/status_manager.rb +39 -0
- data/lib/splitclient-rb/engine/sync_manager.rb +183 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
- data/lib/splitclient-rb/exceptions.rb +26 -0
- data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
- data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
- data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
- data/lib/splitclient-rb/helpers/util.rb +26 -0
- data/lib/splitclient-rb/managers/split_manager.rb +121 -0
- data/lib/splitclient-rb/spec.rb +9 -0
- data/lib/splitclient-rb/split_config.rb +591 -47
- data/lib/splitclient-rb/split_factory.rb +284 -0
- data/lib/splitclient-rb/split_factory_builder.rb +7 -0
- data/lib/splitclient-rb/split_factory_registry.rb +63 -0
- data/lib/splitclient-rb/split_logger.rb +23 -0
- data/lib/splitclient-rb/sse/event_source/client.rb +264 -0
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
- data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
- data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
- data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
- data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +153 -0
- data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
- data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
- data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
- data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
- data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
- data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
- data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
- data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
- data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
- data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
- data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
- data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
- data/lib/splitclient-rb/utilitites.rb +49 -0
- data/lib/splitclient-rb/validators.rb +361 -0
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +177 -25
- data/sonar-project.properties +6 -0
- data/splitclient-rb.gemspec +53 -26
- data/tasks/benchmark_get_treatment.rake +31 -17
- data/tasks/irb.rake +6 -0
- metadata +411 -86
- data/NEWS +0 -9
- data/lib/splitclient-cache/local_store.rb +0 -45
- data/lib/splitclient-engine/impressions/impressions.rb +0 -79
- data/lib/splitclient-engine/matchers/between_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/combining_matcher.rb +0 -94
- data/lib/splitclient-engine/matchers/equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/greater_than_or_equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/less_than_or_equal_to_matcher.rb +0 -48
- data/lib/splitclient-engine/matchers/negation_matcher.rb +0 -54
- data/lib/splitclient-engine/matchers/user_defined_segment_matcher.rb +0 -61
- data/lib/splitclient-engine/matchers/whitelist_matcher.rb +0 -64
- data/lib/splitclient-engine/metrics/binary_search_latency_tracker.rb +0 -122
- data/lib/splitclient-engine/metrics/metrics.rb +0 -158
- data/lib/splitclient-engine/parser/condition.rb +0 -143
- data/lib/splitclient-engine/parser/segment.rb +0 -84
- data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
- data/lib/splitclient-engine/parser/split.rb +0 -68
- data/lib/splitclient-engine/parser/split_adapter.rb +0 -433
- data/lib/splitclient-engine/parser/split_parser.rb +0 -139
- data/lib/splitclient-engine/partitions/treatments.rb +0 -40
- data/lib/splitclient-rb/split_client.rb +0 -156
- data/lib/splitclient-rb_utilitites.rb +0 -26
- data/tasks/console.rake +0 -4
- data/tasks/rspec.rake +0 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
#
|
|
3
|
+
# acts as dto for a condition structure
|
|
4
|
+
#
|
|
5
|
+
class Condition < NoMethodError
|
|
6
|
+
TYPE_ROLLOUT = 'ROLLOUT'.freeze
|
|
7
|
+
TYPE_WHITELIST = 'WHITELIST'.freeze
|
|
8
|
+
#
|
|
9
|
+
# definition of the condition
|
|
10
|
+
#
|
|
11
|
+
# @returns [object] condition values
|
|
12
|
+
attr_accessor :data
|
|
13
|
+
|
|
14
|
+
def initialize(condition, config)
|
|
15
|
+
@data = condition
|
|
16
|
+
@partitions = set_partitions
|
|
17
|
+
@config = config
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create_condition_matcher(matchers)
|
|
21
|
+
CombiningMatcher.new(@config.split_logger, combiner, matchers) if combiner
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# @return [object] the combiner value for this condition
|
|
26
|
+
def combiner
|
|
27
|
+
@data[:matcherGroup][:combiner]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# @return [object] the matcher value for this condition
|
|
32
|
+
def matcher
|
|
33
|
+
@data[:matcherGroup][:matchers].first[:matcherType]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# @return [object] the matchers array value for this condition
|
|
38
|
+
def matchers
|
|
39
|
+
@data[:matcherGroup][:matchers]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# @return [string] condition type
|
|
44
|
+
def type
|
|
45
|
+
@data[:conditionType]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def negation_matcher(matcher)
|
|
49
|
+
NegationMatcher.new(@config.split_logger, matcher)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def matcher_all_keys(_params)
|
|
53
|
+
@matcher_all_keys ||= AllKeysMatcher.new(@config.split_logger)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# returns UserDefinedSegmentMatcher[object]
|
|
57
|
+
def matcher_in_segment(params)
|
|
58
|
+
matcher = params[:matcher]
|
|
59
|
+
segment_name = matcher[:userDefinedSegmentMatcherData] && matcher[:userDefinedSegmentMatcherData][:segmentName]
|
|
60
|
+
|
|
61
|
+
UserDefinedSegmentMatcher.new(params[:segments_repository], segment_name, @config.split_logger)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# returns WhitelistMatcher[object] the whitelist for this condition in case it has a whitelist matcher
|
|
65
|
+
def matcher_whitelist(params)
|
|
66
|
+
result = nil
|
|
67
|
+
matcher = params[:matcher]
|
|
68
|
+
is_user_whitelist = ((matcher[:keySelector]).nil? || (matcher[:keySelector])[:attribute].nil?)
|
|
69
|
+
if is_user_whitelist
|
|
70
|
+
result = (matcher[:whitelistMatcherData])[:whitelist]
|
|
71
|
+
else
|
|
72
|
+
attribute = (matcher[:keySelector])[:attribute]
|
|
73
|
+
white_list = (matcher[:whitelistMatcherData])[:whitelist]
|
|
74
|
+
result = { attribute: attribute, value: white_list }
|
|
75
|
+
end
|
|
76
|
+
WhitelistMatcher.new(result, @config.split_logger, @config.split_validator)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def matcher_equal_to(params)
|
|
80
|
+
matcher = params[:matcher]
|
|
81
|
+
attribute = (matcher[:keySelector])[:attribute]
|
|
82
|
+
value = (matcher[:unaryNumericMatcherData])[:value]
|
|
83
|
+
data_type = (matcher[:unaryNumericMatcherData])[:dataType]
|
|
84
|
+
EqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def matcher_greater_than_or_equal_to(params)
|
|
88
|
+
matcher = params[:matcher]
|
|
89
|
+
attribute = (matcher[:keySelector])[:attribute]
|
|
90
|
+
value = (matcher[:unaryNumericMatcherData])[:value]
|
|
91
|
+
data_type = (matcher[:unaryNumericMatcherData])[:dataType]
|
|
92
|
+
GreaterThanOrEqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def matcher_less_than_or_equal_to(params)
|
|
96
|
+
matcher = params[:matcher]
|
|
97
|
+
attribute = (matcher[:keySelector])[:attribute]
|
|
98
|
+
value = (matcher[:unaryNumericMatcherData])[:value]
|
|
99
|
+
data_type = (matcher[:unaryNumericMatcherData])[:dataType]
|
|
100
|
+
LessThanOrEqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def matcher_between(params)
|
|
104
|
+
matcher = params[:matcher]
|
|
105
|
+
attribute = (matcher[:keySelector])[:attribute]
|
|
106
|
+
start_value = (matcher[:betweenMatcherData])[:start]
|
|
107
|
+
end_value = (matcher[:betweenMatcherData])[:end]
|
|
108
|
+
data_type = (matcher[:betweenMatcherData])[:dataType]
|
|
109
|
+
BetweenMatcher.new({attribute: attribute, start_value: start_value, end_value: end_value, data_type: data_type}, @config.split_logger, @config.split_validator)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def matcher_equal_to_set(params)
|
|
113
|
+
EqualToSetMatcher.new(
|
|
114
|
+
params[:matcher][:keySelector][:attribute],
|
|
115
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
116
|
+
@config.split_logger
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def matcher_contains_any_of_set(params)
|
|
121
|
+
ContainsAnyMatcher.new(
|
|
122
|
+
params[:matcher][:keySelector][:attribute],
|
|
123
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
124
|
+
@config.split_logger
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def matcher_contains_all_of_set(params)
|
|
129
|
+
ContainsAllMatcher.new(
|
|
130
|
+
params[:matcher][:keySelector][:attribute],
|
|
131
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
132
|
+
@config.split_logger
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def matcher_part_of_set(params)
|
|
137
|
+
PartOfSetMatcher.new(
|
|
138
|
+
params[:matcher][:keySelector][:attribute],
|
|
139
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
140
|
+
@config.split_logger
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def matcher_starts_with(params)
|
|
145
|
+
StartsWithMatcher.new(
|
|
146
|
+
params[:matcher][:keySelector][:attribute],
|
|
147
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
148
|
+
@config.split_logger
|
|
149
|
+
)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def matcher_ends_with(params)
|
|
153
|
+
EndsWithMatcher.new(
|
|
154
|
+
params[:matcher][:keySelector][:attribute],
|
|
155
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
156
|
+
@config.split_logger
|
|
157
|
+
)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def matcher_contains_string(params)
|
|
161
|
+
ContainsMatcher.new(
|
|
162
|
+
params[:matcher][:keySelector][:attribute],
|
|
163
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
164
|
+
@config.split_logger, @config.split_validator
|
|
165
|
+
)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def matcher_in_split_treatment(params)
|
|
169
|
+
DependencyMatcher.new(
|
|
170
|
+
params[:matcher][:dependencyMatcherData][:split],
|
|
171
|
+
params[:matcher][:dependencyMatcherData][:treatments],
|
|
172
|
+
@config.split_logger
|
|
173
|
+
)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def matcher_equal_to_boolean(params)
|
|
177
|
+
EqualToBooleanMatcher.new(
|
|
178
|
+
params[:matcher][:keySelector][:attribute],
|
|
179
|
+
params[:matcher][:booleanMatcherData],
|
|
180
|
+
@config.split_logger
|
|
181
|
+
)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def matcher_matches_string(params)
|
|
185
|
+
MatchesStringMatcher.new(
|
|
186
|
+
params[:matcher][:keySelector][:attribute],
|
|
187
|
+
params[:matcher][:stringMatcherData],
|
|
188
|
+
@config.split_logger
|
|
189
|
+
)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def matcher_equal_to_semver(params)
|
|
193
|
+
EqualToSemverMatcher.new(
|
|
194
|
+
params[:matcher][:keySelector][:attribute],
|
|
195
|
+
params[:matcher][:stringMatcherData],
|
|
196
|
+
@config.split_logger, @config.split_validator
|
|
197
|
+
)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def matcher_greater_than_or_equal_to_semver(params)
|
|
201
|
+
GreaterThanOrEqualToSemverMatcher.new(
|
|
202
|
+
params[:matcher][:keySelector][:attribute],
|
|
203
|
+
params[:matcher][:stringMatcherData],
|
|
204
|
+
@config.split_logger, @config.split_validator
|
|
205
|
+
)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def matcher_less_than_or_equal_to_semver(params)
|
|
209
|
+
LessThanOrEqualToSemverMatcher.new(
|
|
210
|
+
params[:matcher][:keySelector][:attribute],
|
|
211
|
+
params[:matcher][:stringMatcherData],
|
|
212
|
+
@config.split_logger, @config.split_validator
|
|
213
|
+
)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def matcher_between_semver(params)
|
|
217
|
+
BetweenSemverMatcher.new(
|
|
218
|
+
params[:matcher][:keySelector][:attribute],
|
|
219
|
+
params[:matcher][:betweenStringMatcherData][:start],
|
|
220
|
+
params[:matcher][:betweenStringMatcherData][:end],
|
|
221
|
+
@config.split_logger, @config.split_validator
|
|
222
|
+
)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def matcher_in_list_semver(params)
|
|
226
|
+
InListSemverMatcher.new(
|
|
227
|
+
params[:matcher][:keySelector][:attribute],
|
|
228
|
+
params[:matcher][:whitelistMatcherData][:whitelist],
|
|
229
|
+
@config.split_logger, @config.split_validator
|
|
230
|
+
)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def matcher_in_rule_based_segment(params)
|
|
234
|
+
matcher = params[:matcher]
|
|
235
|
+
segment_name = matcher[:userDefinedSegmentMatcherData] && matcher[:userDefinedSegmentMatcherData][:segmentName]
|
|
236
|
+
|
|
237
|
+
RuleBasedSegmentMatcher.new(params[:segments_repository], params[:rule_based_segments_repository], segment_name, @config)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
#
|
|
241
|
+
# @return [object] the negate value for this condition
|
|
242
|
+
def negate
|
|
243
|
+
@data[:matcherGroup][:matchers].first[:negate]
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
#
|
|
247
|
+
# @return [object] the array of partitions for this condition
|
|
248
|
+
attr_reader :partitions
|
|
249
|
+
|
|
250
|
+
#
|
|
251
|
+
# converts the partitions hash for this condition into an array of partition objects
|
|
252
|
+
#
|
|
253
|
+
# @return [void]
|
|
254
|
+
def set_partitions
|
|
255
|
+
partitions_list = []
|
|
256
|
+
return partitions_list unless @data.key?(:partitions) or @data.key?('partitions')
|
|
257
|
+
|
|
258
|
+
@data[:partitions].each do |p|
|
|
259
|
+
partition = SplitIoClient::Partition.new(p)
|
|
260
|
+
partitions_list << partition
|
|
261
|
+
end
|
|
262
|
+
partitions_list
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
#
|
|
266
|
+
# @return [boolean] true if the condition is empty false otherwise
|
|
267
|
+
def empty?
|
|
268
|
+
@data.empty?
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
module Engine
|
|
3
|
+
module Parser
|
|
4
|
+
class Evaluator
|
|
5
|
+
def initialize(segments_repository, splits_repository, rb_segment_repository, config)
|
|
6
|
+
@splits_repository = splits_repository
|
|
7
|
+
@segments_repository = segments_repository
|
|
8
|
+
@rb_segment_repository = rb_segment_repository
|
|
9
|
+
@config = config
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def evaluate_feature_flag(keys, feature_flag, attributes = nil)
|
|
13
|
+
# DependencyMatcher here, split is actually a split_name in this case
|
|
14
|
+
cache_result = feature_flag.is_a? String
|
|
15
|
+
feature_flag = @splits_repository.get_split(feature_flag) if cache_result
|
|
16
|
+
evaluate_treatment(keys, feature_flag, attributes)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def evaluate_treatment(keys, feature_flag, attributes)
|
|
22
|
+
if Models::Split.archived?(feature_flag)
|
|
23
|
+
return treatment_hash(Models::Label::ARCHIVED, Models::Treatment::CONTROL, feature_flag[:changeNumber])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
treatment = if Models::Split.matchable?(feature_flag)
|
|
27
|
+
match(feature_flag, keys, attributes)
|
|
28
|
+
else
|
|
29
|
+
treatment_hash(Models::Label::KILLED, feature_flag[:defaultTreatment], feature_flag[:changeNumber], split_configurations(feature_flag[:defaultTreatment], feature_flag))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
treatment
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def split_configurations(treatment, split)
|
|
36
|
+
return nil if split[:configurations].nil?
|
|
37
|
+
split[:configurations][treatment.to_sym]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def match(split, keys, attributes)
|
|
41
|
+
|
|
42
|
+
return treatment_hash(Models::Label::PREREQUISITES_NOT_MET, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split)) unless check_prerequisites_matcher(split, keys, attributes)
|
|
43
|
+
|
|
44
|
+
in_rollout = false
|
|
45
|
+
key = keys[:bucketing_key] ? keys[:bucketing_key] : keys[:matching_key]
|
|
46
|
+
legacy_algo = (split[:algo] == 1 || split[:algo] == nil) ? true : false
|
|
47
|
+
splitter = Splitter.new
|
|
48
|
+
|
|
49
|
+
split[:conditions].each do |c|
|
|
50
|
+
condition = SplitIoClient::Condition.new(c, @config)
|
|
51
|
+
|
|
52
|
+
next if condition.empty?
|
|
53
|
+
|
|
54
|
+
if !in_rollout && condition.type == SplitIoClient::Condition::TYPE_ROLLOUT
|
|
55
|
+
if split[:trafficAllocation] < 100
|
|
56
|
+
bucket = splitter.bucket(splitter.count_hash(key, split[:trafficAllocationSeed].to_i, legacy_algo))
|
|
57
|
+
|
|
58
|
+
if bucket > split[:trafficAllocation]
|
|
59
|
+
return treatment_hash(Models::Label::NOT_IN_SPLIT, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
in_rollout = true
|
|
64
|
+
end
|
|
65
|
+
condition_matched = Helpers::EvaluatorHelper::matcher_type(condition, @segments_repository, @rb_segment_repository).match?(
|
|
66
|
+
matching_key: keys[:matching_key],
|
|
67
|
+
bucketing_key: keys[:bucketing_key],
|
|
68
|
+
evaluator: self,
|
|
69
|
+
attributes: attributes
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
next unless condition_matched
|
|
73
|
+
|
|
74
|
+
result = splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
|
|
75
|
+
|
|
76
|
+
return treatment_from_result(result, split, c)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def treatment_from_result(result, split, condition)
|
|
85
|
+
if result.nil?
|
|
86
|
+
return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
|
|
87
|
+
else
|
|
88
|
+
return treatment_hash(condition[:label], result, split[:changeNumber],split_configurations(result, split))
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def treatment_hash(label, treatment, change_number = nil, configurations = nil)
|
|
93
|
+
{ label: label, treatment: treatment, change_number: change_number, config: configurations }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def check_prerequisites_matcher(split, keys, attributes)
|
|
97
|
+
if split.key?(:prerequisites) && !split[:prerequisites].nil?
|
|
98
|
+
prerequisites_matcher = SplitIoClient::PrerequisitesMatcher.new(split[:prerequisites], @config.split_logger)
|
|
99
|
+
return prerequisites_matcher.match?(
|
|
100
|
+
matching_key: keys[:matching_key],
|
|
101
|
+
bucketing_key: keys[:bucketing_key],
|
|
102
|
+
evaluator: self,
|
|
103
|
+
attributes: attributes
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module SplitIoClient
|
|
2
|
-
|
|
3
2
|
#
|
|
4
3
|
# acts as dto for a partition structure
|
|
5
4
|
#
|
|
@@ -30,8 +29,7 @@ module SplitIoClient
|
|
|
30
29
|
#
|
|
31
30
|
# @return [boolean] true if the partition is empty false otherwise
|
|
32
31
|
def is_empty?
|
|
33
|
-
@data.empty?
|
|
32
|
+
@data.empty?
|
|
34
33
|
end
|
|
35
34
|
end
|
|
36
|
-
|
|
37
|
-
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
class PushManager
|
|
6
|
+
def initialize(config, sse_handler, api_key, telemetry_runtime_producer)
|
|
7
|
+
@config = config
|
|
8
|
+
@sse_handler = sse_handler
|
|
9
|
+
@auth_api_client = AuthApiClient.new(@config, telemetry_runtime_producer)
|
|
10
|
+
@api_key = api_key
|
|
11
|
+
@back_off = Engine::BackOff.new(@config.auth_retry_back_off_base, 1)
|
|
12
|
+
@telemetry_runtime_producer = telemetry_runtime_producer
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def start_sse
|
|
16
|
+
response = @auth_api_client.authenticate(@api_key)
|
|
17
|
+
@config.logger.debug("Auth service response push_enabled: #{response[:push_enabled]}") if @config.debug_enabled
|
|
18
|
+
|
|
19
|
+
if response[:push_enabled] && @sse_handler.start(response[:token], response[:channels])
|
|
20
|
+
schedule_next_token_refresh(response[:exp])
|
|
21
|
+
@back_off.reset
|
|
22
|
+
record_telemetry(response[:exp])
|
|
23
|
+
|
|
24
|
+
return true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
stop_sse
|
|
28
|
+
schedule_next_token_refresh(@back_off.interval) if response[:retry]
|
|
29
|
+
false
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
@config.logger.error("start_sse: #{e.inspect}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def stop_sse
|
|
35
|
+
@sse_handler.stop
|
|
36
|
+
SplitIoClient::Helpers::ThreadHelper.stop(:schedule_next_token_refresh, @config)
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
@config.logger.error(e.inspect)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def schedule_next_token_refresh(time)
|
|
44
|
+
@config.threads[:schedule_next_token_refresh] = Thread.new { refresh_token_task(time) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def refresh_token_task(time)
|
|
48
|
+
@config.logger.debug("schedule_next_token_refresh refresh in #{time} seconds.") if @config.debug_enabled
|
|
49
|
+
|
|
50
|
+
sleep(time)
|
|
51
|
+
|
|
52
|
+
@config.logger.debug('schedule_next_token_refresh starting ...') if @config.debug_enabled
|
|
53
|
+
@sse_handler.stop
|
|
54
|
+
|
|
55
|
+
start_sse
|
|
56
|
+
rescue StandardError => e
|
|
57
|
+
@config.logger.debug("schedule_next_token_refresh error: #{e.inspect}") if @config.debug_enabled
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def record_telemetry(time)
|
|
61
|
+
data = (Time.now.to_f * 1000.0).to_i + (time * 1000.0).to_i
|
|
62
|
+
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::TOKEN_REFRESH, data)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
class StatusManager
|
|
6
|
+
def initialize(config, internal_events_queue)
|
|
7
|
+
@config = config
|
|
8
|
+
@sdk_ready = Concurrent::CountDownLatch.new(1)
|
|
9
|
+
@internal_events_queue = internal_events_queue
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def ready?
|
|
13
|
+
return true if @config.consumer?
|
|
14
|
+
|
|
15
|
+
@sdk_ready.wait(0)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ready!
|
|
19
|
+
return if ready?
|
|
20
|
+
|
|
21
|
+
@sdk_ready.count_down
|
|
22
|
+
@config.logger.info('SplitIO SDK is ready')
|
|
23
|
+
@internal_events_queue.push(
|
|
24
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
25
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::SDK_READY, nil
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def wait_until_ready(seconds = nil)
|
|
31
|
+
return if @config.consumer?
|
|
32
|
+
|
|
33
|
+
timeout = seconds || @config.block_until_ready
|
|
34
|
+
|
|
35
|
+
raise SDKBlockerTimeoutExpiredException, 'SDK start up timeout expired' unless @sdk_ready.wait(timeout)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
class SyncManager
|
|
6
|
+
SYNC_MODE_STREAMING = 0
|
|
7
|
+
SYNC_MODE_POLLING = 1
|
|
8
|
+
|
|
9
|
+
def initialize(config, synchronizer, telemetry_runtime_producer, telemetry_synchronizer,
|
|
10
|
+
status_manager, sse_handler, push_manager, status_queue)
|
|
11
|
+
@config = config
|
|
12
|
+
@synchronizer = synchronizer
|
|
13
|
+
@telemetry_runtime_producer = telemetry_runtime_producer
|
|
14
|
+
@telemetry_synchronizer = telemetry_synchronizer
|
|
15
|
+
@status_manager = status_manager
|
|
16
|
+
@sse_handler = sse_handler
|
|
17
|
+
@push_manager = push_manager
|
|
18
|
+
@status_queue = status_queue
|
|
19
|
+
@sse_connected = Concurrent::AtomicBoolean.new(false)
|
|
20
|
+
@back_off = Engine::BackOff.new(1, 3)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def start
|
|
24
|
+
start_thread
|
|
25
|
+
PhusionPassenger.on_event(:starting_worker_process) { |forked| start_thread if forked } if defined?(PhusionPassenger)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def start_consumer
|
|
29
|
+
start_consumer_thread
|
|
30
|
+
PhusionPassenger.on_event(:starting_worker_process) { |forked| start_consumer_thread if forked } if defined?(PhusionPassenger)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def start_thread
|
|
36
|
+
@config.threads[:start_sdk] = Thread.new do
|
|
37
|
+
sleep(0.5) until @synchronizer.sync_all(false)
|
|
38
|
+
|
|
39
|
+
@status_manager.ready!
|
|
40
|
+
@telemetry_synchronizer.synchronize_config
|
|
41
|
+
@synchronizer.start_periodic_data_recording
|
|
42
|
+
connected = false
|
|
43
|
+
|
|
44
|
+
if @config.streaming_enabled
|
|
45
|
+
@config.logger.debug('Starting Streaming mode ...') if @config.debug_enabled
|
|
46
|
+
start_push_status_monitor
|
|
47
|
+
connected = @push_manager.start_sse
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
unless connected
|
|
51
|
+
@config.logger.debug('Starting Polling mode ...') if @config.debug_enabled
|
|
52
|
+
@synchronizer.start_periodic_fetch
|
|
53
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def start_consumer_thread
|
|
59
|
+
@config.threads[:start_sdk_consumer] = Thread.new do
|
|
60
|
+
@status_manager.ready!
|
|
61
|
+
@telemetry_synchronizer.synchronize_config
|
|
62
|
+
@synchronizer.start_periodic_data_recording
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def process_subsystem_ready
|
|
67
|
+
@synchronizer.stop_periodic_fetch
|
|
68
|
+
@synchronizer.sync_all
|
|
69
|
+
@sse_handler.start_workers
|
|
70
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_STREAMING)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def process_subsystem_down
|
|
74
|
+
@sse_handler.stop_workers
|
|
75
|
+
@synchronizer.start_periodic_fetch
|
|
76
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def process_push_shutdown
|
|
80
|
+
@push_manager.stop_sse
|
|
81
|
+
@sse_handler.stop_workers
|
|
82
|
+
@synchronizer.start_periodic_fetch
|
|
83
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
84
|
+
rescue StandardError => e
|
|
85
|
+
@config.logger.error("process_push_shutdown error: #{e.inspect}")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def process_connected
|
|
89
|
+
if @sse_connected.value
|
|
90
|
+
@config.logger.debug('Streaming already connected.') if @config.debug_enabled
|
|
91
|
+
return
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
@sse_connected.make_true
|
|
95
|
+
@synchronizer.stop_periodic_fetch
|
|
96
|
+
@synchronizer.sync_all
|
|
97
|
+
@sse_handler.start_workers
|
|
98
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_STREAMING)
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
@config.logger.error("process_connected error: #{e.inspect}")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def process_forced_stop
|
|
104
|
+
unless @sse_connected.value
|
|
105
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
106
|
+
return
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
@sse_connected.make_false
|
|
110
|
+
@synchronizer.start_periodic_fetch
|
|
111
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
112
|
+
rescue StandardError => e
|
|
113
|
+
@config.logger.error("process_connected error: #{e.inspect}")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def process_disconnect(reconnect)
|
|
117
|
+
unless @sse_connected.value || reconnect
|
|
118
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
119
|
+
return
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
@sse_connected.make_false
|
|
123
|
+
@sse_handler.stop_workers
|
|
124
|
+
@synchronizer.start_periodic_fetch
|
|
125
|
+
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
126
|
+
|
|
127
|
+
if reconnect
|
|
128
|
+
wait_interval = @back_off.interval
|
|
129
|
+
@config.logger.debug("Retrying streaming connection in: #{wait_interval} seconds")
|
|
130
|
+
sleep(wait_interval)
|
|
131
|
+
@push_manager.stop_sse
|
|
132
|
+
@synchronizer.sync_all
|
|
133
|
+
@push_manager.start_sse
|
|
134
|
+
end
|
|
135
|
+
rescue StandardError => e
|
|
136
|
+
@config.logger.error("process_disconnect error: #{e.inspect}")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def record_telemetry(type, data)
|
|
140
|
+
@telemetry_runtime_producer.record_streaming_event(type, data)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def start_push_status_monitor
|
|
144
|
+
@config.threads[:push_status_handler] = Thread.new do
|
|
145
|
+
@config.logger.debug('Starting push status handler ...') if @config.debug_enabled
|
|
146
|
+
incoming_push_status_handler
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def incoming_push_status_handler
|
|
151
|
+
while (status = @status_queue.pop)
|
|
152
|
+
@config.logger.debug("Push status handler dequeue #{status}") if @config.debug_enabled
|
|
153
|
+
|
|
154
|
+
case status
|
|
155
|
+
when Constants::PUSH_CONNECTED
|
|
156
|
+
@back_off.reset
|
|
157
|
+
process_connected
|
|
158
|
+
when Constants::PUSH_RETRYABLE_ERROR
|
|
159
|
+
process_disconnect(true)
|
|
160
|
+
when Constants::PUSH_FORCED_STOP
|
|
161
|
+
process_forced_stop
|
|
162
|
+
when Constants::PUSH_NONRETRYABLE_ERROR
|
|
163
|
+
process_disconnect(false)
|
|
164
|
+
when Constants::PUSH_SUBSYSTEM_DOWN
|
|
165
|
+
process_subsystem_down
|
|
166
|
+
when Constants::PUSH_SUBSYSTEM_READY
|
|
167
|
+
process_subsystem_ready
|
|
168
|
+
when Constants::PUSH_SUBSYSTEM_OFF
|
|
169
|
+
process_push_shutdown
|
|
170
|
+
else
|
|
171
|
+
log_if_debug('Incorrect push status type.')
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
rescue StandardError => e
|
|
175
|
+
@config.logger.error("Push status handler error: #{e.inspect}")
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def log_if_debug(msg)
|
|
180
|
+
@config.logger.debug(msg) if @config.debug_enabled
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|