splitclient-rb 8.5.0-java → 8.6.0-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 +4 -4
- data/CHANGES.txt +4 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +9 -7
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +122 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +7 -0
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +19 -11
- data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +2 -1
- data/lib/splitclient-rb/clients/split_client.rb +2 -0
- data/lib/splitclient-rb/engine/api/client.rb +8 -0
- data/lib/splitclient-rb/engine/api/splits.rb +99 -23
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +3 -1
- data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
- data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +75 -0
- data/lib/splitclient-rb/engine/models/label.rb +1 -0
- data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +9 -0
- data/lib/splitclient-rb/engine/parser/evaluator.rb +24 -30
- data/lib/splitclient-rb/engine/synchronizer.rb +33 -13
- data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +38 -7
- data/lib/splitclient-rb/helpers/util.rb +12 -3
- data/lib/splitclient-rb/spec.rb +1 -1
- data/lib/splitclient-rb/split_config.rb +4 -0
- data/lib/splitclient-rb/split_factory.rb +5 -3
- data/lib/splitclient-rb/sse/event_source/event_types.rb +1 -0
- data/lib/splitclient-rb/sse/notification_processor.rb +3 -1
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +58 -19
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +6 -0
- data/splitclient-rb.gemspec +2 -2
- metadata +12 -6
@@ -2,9 +2,10 @@ module SplitIoClient
|
|
2
2
|
module Engine
|
3
3
|
module Parser
|
4
4
|
class Evaluator
|
5
|
-
def initialize(segments_repository, splits_repository, config)
|
5
|
+
def initialize(segments_repository, splits_repository, rb_segment_repository, config)
|
6
6
|
@splits_repository = splits_repository
|
7
7
|
@segments_repository = segments_repository
|
8
|
+
@rb_segment_repository = rb_segment_repository
|
8
9
|
@config = config
|
9
10
|
end
|
10
11
|
|
@@ -37,6 +38,9 @@ module SplitIoClient
|
|
37
38
|
end
|
38
39
|
|
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
|
+
|
40
44
|
in_rollout = false
|
41
45
|
key = keys[:bucketing_key] ? keys[:bucketing_key] : keys[:matching_key]
|
42
46
|
legacy_algo = (split[:algo] == 1 || split[:algo] == nil) ? true : false
|
@@ -58,8 +62,7 @@ module SplitIoClient
|
|
58
62
|
|
59
63
|
in_rollout = true
|
60
64
|
end
|
61
|
-
|
62
|
-
condition_matched = matcher_type(condition).match?(
|
65
|
+
condition_matched = Helpers::EvaluatorHelper::matcher_type(condition, @segments_repository, @rb_segment_repository).match?(
|
63
66
|
matching_key: keys[:matching_key],
|
64
67
|
bucketing_key: keys[:bucketing_key],
|
65
68
|
evaluator: self,
|
@@ -70,35 +73,19 @@ module SplitIoClient
|
|
70
73
|
|
71
74
|
result = splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
|
72
75
|
|
73
|
-
|
74
|
-
return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
|
75
|
-
else
|
76
|
-
return treatment_hash(c[:label], result, split[:changeNumber],split_configurations(result, split))
|
77
|
-
end
|
76
|
+
return treatment_from_result(result, split, c)
|
78
77
|
end
|
79
78
|
|
80
79
|
treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
|
81
80
|
end
|
82
81
|
|
83
|
-
|
84
|
-
matchers = []
|
85
|
-
|
86
|
-
@segments_repository.adapter.pipelined do
|
87
|
-
condition.matchers.each do |matcher|
|
88
|
-
matchers << if matcher[:negate]
|
89
|
-
condition.negation_matcher(matcher_instance(matcher[:matcherType], condition, matcher))
|
90
|
-
else
|
91
|
-
matcher_instance(matcher[:matcherType], condition, matcher)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
final_matcher = condition.create_condition_matcher(matchers)
|
82
|
+
private
|
97
83
|
|
98
|
-
|
99
|
-
|
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))
|
100
87
|
else
|
101
|
-
|
88
|
+
return treatment_hash(condition[:label], result, split[:changeNumber],split_configurations(result, split))
|
102
89
|
end
|
103
90
|
end
|
104
91
|
|
@@ -106,11 +93,18 @@ module SplitIoClient
|
|
106
93
|
{ label: label, treatment: treatment, change_number: change_number, config: configurations }
|
107
94
|
end
|
108
95
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
114
108
|
end
|
115
109
|
end
|
116
110
|
end
|
@@ -15,6 +15,7 @@ module SplitIoClient
|
|
15
15
|
)
|
16
16
|
@splits_repository = repositories[:splits]
|
17
17
|
@segments_repository = repositories[:segments]
|
18
|
+
@rule_based_segments_repository = repositories[:rule_based_segments]
|
18
19
|
@impressions_repository = repositories[:impressions]
|
19
20
|
@events_repository = repositories[:events]
|
20
21
|
@config = config
|
@@ -63,12 +64,12 @@ module SplitIoClient
|
|
63
64
|
@segment_fetcher.stop_segments_thread
|
64
65
|
end
|
65
66
|
|
66
|
-
def fetch_splits(target_change_number)
|
67
|
-
return if target_change_number
|
67
|
+
def fetch_splits(target_change_number, rbs_target_change_number)
|
68
|
+
return if check_exit_conditions(target_change_number, rbs_target_change_number)
|
68
69
|
|
69
70
|
fetch_options = { cache_control_headers: true, till: nil }
|
70
71
|
|
71
|
-
result = attempt_splits_sync(target_change_number,
|
72
|
+
result = attempt_splits_sync(target_change_number, rbs_target_change_number,
|
72
73
|
fetch_options,
|
73
74
|
@config.on_demand_fetch_max_retries,
|
74
75
|
@config.on_demand_fetch_retry_delay_seconds,
|
@@ -82,8 +83,13 @@ module SplitIoClient
|
|
82
83
|
return
|
83
84
|
end
|
84
85
|
|
85
|
-
|
86
|
-
|
86
|
+
if target_change_number != 0
|
87
|
+
fetch_options[:till] = target_change_number
|
88
|
+
else
|
89
|
+
fetch_options[:till] = rbs_target_change_number
|
90
|
+
end
|
91
|
+
|
92
|
+
result = attempt_splits_sync(target_change_number, rbs_target_change_number,
|
87
93
|
fetch_options,
|
88
94
|
ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES,
|
89
95
|
nil,
|
@@ -91,12 +97,7 @@ module SplitIoClient
|
|
91
97
|
|
92
98
|
attempts = ON_DEMAND_FETCH_BACKOFF_MAX_RETRIES - result[:remaining_attempts]
|
93
99
|
|
94
|
-
|
95
|
-
@segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty?
|
96
|
-
@config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled
|
97
|
-
else
|
98
|
-
@config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled
|
99
|
-
end
|
100
|
+
process_result(result, attempts)
|
100
101
|
rescue StandardError => e
|
101
102
|
@config.log_found_exception(__method__.to_s, e)
|
102
103
|
end
|
@@ -139,6 +140,15 @@ module SplitIoClient
|
|
139
140
|
|
140
141
|
private
|
141
142
|
|
143
|
+
def process_result(result, attempts)
|
144
|
+
if result[:success]
|
145
|
+
@segment_fetcher.fetch_segments_if_not_exists(result[:segment_names], true) unless result[:segment_names].empty?
|
146
|
+
@config.logger.debug("Refresh completed bypassing the CDN in #{attempts} attempts.") if @config.debug_enabled
|
147
|
+
else
|
148
|
+
@config.logger.debug("No changes fetched after #{attempts} attempts with CDN bypassed.") if @config.debug_enabled
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
142
152
|
def attempt_segment_sync(name, target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
|
143
153
|
remaining_attempts = max_retries
|
144
154
|
@segments_sync_backoff.reset
|
@@ -156,7 +166,7 @@ module SplitIoClient
|
|
156
166
|
end
|
157
167
|
end
|
158
168
|
|
159
|
-
def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
|
169
|
+
def attempt_splits_sync(target_cn, rbs_target_cn, fetch_options, max_retries, retry_delay_seconds, with_backoff)
|
160
170
|
remaining_attempts = max_retries
|
161
171
|
@splits_sync_backoff.reset
|
162
172
|
|
@@ -165,7 +175,7 @@ module SplitIoClient
|
|
165
175
|
|
166
176
|
result = @split_fetcher.fetch_splits(fetch_options)
|
167
177
|
|
168
|
-
return sync_result(true, remaining_attempts, result[:segment_names]) if target_cn
|
178
|
+
return sync_result(true, remaining_attempts, result[:segment_names]) if check_exit_conditions(target_cn, rbs_target_cn)
|
169
179
|
return sync_result(false, remaining_attempts, result[:segment_names]) if remaining_attempts <= 0
|
170
180
|
|
171
181
|
delay = with_backoff ? @splits_sync_backoff.interval : retry_delay_seconds
|
@@ -206,6 +216,16 @@ module SplitIoClient
|
|
206
216
|
|
207
217
|
splits_result[:success] && @segment_fetcher.fetch_segments
|
208
218
|
end
|
219
|
+
|
220
|
+
def check_exit_conditions(target_change_number, rbs_target_change_number)
|
221
|
+
return true if rbs_target_change_number == 0 and target_change_number == 0
|
222
|
+
|
223
|
+
return target_change_number <= @splits_repository.get_change_number.to_i if rbs_target_change_number == 0
|
224
|
+
|
225
|
+
return rbs_target_change_number <= @rule_based_segments_repository.get_change_number.to_i if target_change_number == 0
|
226
|
+
|
227
|
+
return (target_change_number <= @splits_repository.get_change_number.to_i and rbs_target_change_number <= @rule_based_segments_repository.get_change_number.to_i)
|
228
|
+
end
|
209
229
|
end
|
210
230
|
end
|
211
231
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Helpers
|
5
|
+
class EvaluatorHelper
|
6
|
+
def self.matcher_type(condition, segments_repository, rb_segment_repository)
|
7
|
+
matchers = []
|
8
|
+
segments_repository.adapter.pipelined do
|
9
|
+
condition.matchers.each do |matcher|
|
10
|
+
matchers << if matcher[:negate]
|
11
|
+
condition.negation_matcher(matcher_instance(matcher[:matcherType], condition,
|
12
|
+
matcher, segments_repository,
|
13
|
+
rb_segment_repository))
|
14
|
+
else
|
15
|
+
matcher_instance(matcher[:matcherType], condition, matcher, segments_repository, rb_segment_repository)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
final_matcher = condition.create_condition_matcher(matchers)
|
20
|
+
|
21
|
+
if final_matcher.nil?
|
22
|
+
config.logger.error('Invalid matcher type')
|
23
|
+
else
|
24
|
+
final_matcher
|
25
|
+
end
|
26
|
+
final_matcher
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.matcher_instance(type, condition, matcher, segments_repository, rb_segment_repository)
|
30
|
+
condition.send(
|
31
|
+
"matcher_#{type.downcase}",
|
32
|
+
matcher: matcher, segments_repository: segments_repository, rule_based_segments_repository: rb_segment_repository
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module SplitIoClient
|
4
4
|
module Helpers
|
5
5
|
class RepositoryHelper
|
6
|
-
def self.update_feature_flag_repository(feature_flag_repository, feature_flags, change_number, config)
|
6
|
+
def self.update_feature_flag_repository(feature_flag_repository, feature_flags, change_number, config, clear_storage)
|
7
7
|
to_add = []
|
8
8
|
to_delete = []
|
9
9
|
feature_flags.each do |feature_flag|
|
@@ -13,18 +13,49 @@ module SplitIoClient
|
|
13
13
|
next
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
feature_flag[:impressionsDisabled] = false
|
18
|
-
if config.debug_enabled
|
19
|
-
config.logger.debug("feature flag (#{feature_flag[:name]}) does not have impressionsDisabled field, setting it to false")
|
20
|
-
end
|
21
|
-
end
|
16
|
+
feature_flag = check_missing_elements(feature_flag, config)
|
22
17
|
|
23
18
|
config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled
|
24
19
|
to_add.push(feature_flag)
|
25
20
|
end
|
21
|
+
feature_flag_repository.clear if clear_storage
|
26
22
|
feature_flag_repository.update(to_add, to_delete, change_number)
|
27
23
|
end
|
24
|
+
|
25
|
+
def self.check_missing_elements(feature_flag, config)
|
26
|
+
unless feature_flag.key?(:impressionsDisabled)
|
27
|
+
feature_flag[:impressionsDisabled] = false
|
28
|
+
if config.debug_enabled
|
29
|
+
config.logger.debug("feature flag (#{feature_flag[:name]}) does not have impressionsDisabled field, setting it to false")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
unless feature_flag.key?(:prerequisites)
|
34
|
+
feature_flag[:prerequisites] = []
|
35
|
+
if config.debug_enabled
|
36
|
+
config.logger.debug("feature flag (#{feature_flag[:name]}) does not have prerequisites field, setting it to empty array")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
feature_flag
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.update_rule_based_segment_repository(rule_based_segment_repository, rule_based_segments, change_number, config)
|
44
|
+
to_add = []
|
45
|
+
to_delete = []
|
46
|
+
rule_based_segments.each do |rule_based_segment|
|
47
|
+
if Engine::Models::Split.archived?(rule_based_segment)
|
48
|
+
config.logger.debug("removing rule based segment from store(#{rule_based_segment})") if config.debug_enabled
|
49
|
+
to_delete.push(rule_based_segment)
|
50
|
+
next
|
51
|
+
end
|
52
|
+
|
53
|
+
config.logger.debug("storing rule based segment (#{rule_based_segment[:name]})") if config.debug_enabled
|
54
|
+
to_add.push(rule_based_segment)
|
55
|
+
end
|
56
|
+
|
57
|
+
rule_based_segment_repository.update(to_add, to_delete, change_number)
|
58
|
+
end
|
28
59
|
end
|
29
60
|
end
|
30
61
|
end
|
@@ -3,15 +3,24 @@
|
|
3
3
|
module SplitIoClient
|
4
4
|
module Helpers
|
5
5
|
class Util
|
6
|
-
def self.
|
7
|
-
|
6
|
+
def self.segment_names_by_object(object, matcher_type)
|
7
|
+
object[:conditions].each_with_object(Set.new) do |condition, names|
|
8
8
|
condition[:matcherGroup][:matchers].each do |matcher|
|
9
|
-
next if matcher[:userDefinedSegmentMatcherData].nil?
|
9
|
+
next if matcher[:userDefinedSegmentMatcherData].nil? || matcher[:matcherType] != matcher_type
|
10
10
|
|
11
11
|
names << matcher[:userDefinedSegmentMatcherData][:segmentName]
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
|
+
|
16
|
+
def self.segment_names_in_rb_segment(object, matcher_type)
|
17
|
+
names = Set.new
|
18
|
+
names.merge segment_names_by_object(object, matcher_type)
|
19
|
+
object[:excluded][:segments].each do |segment|
|
20
|
+
names.add(segment[:name]) if segment[:type] == SplitIoClient::Engine::Models::SegmentType::STANDARD
|
21
|
+
end
|
22
|
+
names
|
23
|
+
end
|
15
24
|
end
|
16
25
|
end
|
17
26
|
end
|
data/lib/splitclient-rb/spec.rb
CHANGED
@@ -55,7 +55,7 @@ module SplitIoClient
|
|
55
55
|
|
56
56
|
@status_manager = Engine::StatusManager.new(@config)
|
57
57
|
@split_validator = SplitIoClient::Validators.new(@config)
|
58
|
-
@evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @config)
|
58
|
+
@evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @rule_based_segment_repository, @config)
|
59
59
|
|
60
60
|
start!
|
61
61
|
|
@@ -154,6 +154,7 @@ module SplitIoClient
|
|
154
154
|
segments: @segments_repository,
|
155
155
|
impressions: @impressions_repository,
|
156
156
|
events: @events_repository,
|
157
|
+
rule_based_segments: @rule_based_segment_repository
|
157
158
|
}
|
158
159
|
end
|
159
160
|
|
@@ -178,7 +179,7 @@ module SplitIoClient
|
|
178
179
|
end
|
179
180
|
|
180
181
|
def build_fetchers
|
181
|
-
@split_fetcher = SplitFetcher.new(@splits_repository, @api_key, @config, @runtime_producer)
|
182
|
+
@split_fetcher = SplitFetcher.new(@splits_repository, @rule_based_segment_repository, @api_key, @config, @runtime_producer)
|
182
183
|
@segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @config, @runtime_producer)
|
183
184
|
end
|
184
185
|
|
@@ -198,7 +199,7 @@ module SplitIoClient
|
|
198
199
|
|
199
200
|
def build_streaming_components
|
200
201
|
@push_status_queue = Queue.new
|
201
|
-
splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher)
|
202
|
+
splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher, @rule_based_segment_repository)
|
202
203
|
segments_worker = SSE::Workers::SegmentsWorker.new(@synchronizer, @config, @segments_repository)
|
203
204
|
notification_manager_keeper = SSE::NotificationManagerKeeper.new(@config, @runtime_producer, @push_status_queue)
|
204
205
|
notification_processor = SSE::NotificationProcessor.new(@config, splits_worker, segments_worker)
|
@@ -220,6 +221,7 @@ module SplitIoClient
|
|
220
221
|
end
|
221
222
|
@splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter)
|
222
223
|
@segments_repository = SegmentsRepository.new(@config)
|
224
|
+
@rule_based_segment_repository = RuleBasedSegmentsRepository.new(@config)
|
223
225
|
@impressions_repository = ImpressionsRepository.new(@config)
|
224
226
|
@events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
|
225
227
|
end
|
@@ -13,6 +13,8 @@ module SplitIoClient
|
|
13
13
|
case incoming_notification.data['type']
|
14
14
|
when SSE::EventSource::EventTypes::SPLIT_UPDATE
|
15
15
|
process_split_update(incoming_notification)
|
16
|
+
when SSE::EventSource::EventTypes::RB_SEGMENT_UPDATE
|
17
|
+
process_split_update(incoming_notification)
|
16
18
|
when SSE::EventSource::EventTypes::SPLIT_KILL
|
17
19
|
process_split_kill(incoming_notification)
|
18
20
|
when SSE::EventSource::EventTypes::SEGMENT_UPDATE
|
@@ -25,7 +27,7 @@ module SplitIoClient
|
|
25
27
|
private
|
26
28
|
|
27
29
|
def process_split_update(notification)
|
28
|
-
@config.logger.debug("
|
30
|
+
@config.logger.debug("#{notification.event_type} notification received: #{notification}") if @config.debug_enabled
|
29
31
|
@splits_worker.add_to_queue(notification)
|
30
32
|
end
|
31
33
|
|
@@ -4,7 +4,8 @@ module SplitIoClient
|
|
4
4
|
module SSE
|
5
5
|
module Workers
|
6
6
|
class SplitsWorker
|
7
|
-
def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer,
|
7
|
+
def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer,
|
8
|
+
segment_fetcher, rule_based_segment_repository)
|
8
9
|
@synchronizer = synchronizer
|
9
10
|
@config = config
|
10
11
|
@feature_flags_repository = feature_flags_repository
|
@@ -12,6 +13,7 @@ module SplitIoClient
|
|
12
13
|
@running = Concurrent::AtomicBoolean.new(false)
|
13
14
|
@telemetry_runtime_producer = telemetry_runtime_producer
|
14
15
|
@segment_fetcher = segment_fetcher
|
16
|
+
@rule_based_segment_repository = rule_based_segment_repository
|
15
17
|
end
|
16
18
|
|
17
19
|
def start
|
@@ -54,7 +56,10 @@ module SplitIoClient
|
|
54
56
|
case notification.data['type']
|
55
57
|
when SSE::EventSource::EventTypes::SPLIT_UPDATE
|
56
58
|
success = update_feature_flag(notification)
|
57
|
-
@synchronizer.fetch_splits(notification.data['changeNumber']) unless success
|
59
|
+
@synchronizer.fetch_splits(notification.data['changeNumber'], 0) unless success
|
60
|
+
when SSE::EventSource::EventTypes::RB_SEGMENT_UPDATE
|
61
|
+
success = update_rule_based_segment(notification)
|
62
|
+
@synchronizer.fetch_splits(0, notification.data['changeNumber']) unless success
|
58
63
|
when SSE::EventSource::EventTypes::SPLIT_KILL
|
59
64
|
kill_feature_flag(notification)
|
60
65
|
end
|
@@ -65,11 +70,12 @@ module SplitIoClient
|
|
65
70
|
return true if @feature_flags_repository.get_change_number.to_i >= notification.data['changeNumber']
|
66
71
|
return false unless !notification.data['d'].nil? && @feature_flags_repository.get_change_number == notification.data['pcn']
|
67
72
|
|
68
|
-
new_split =
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
new_split = update_feature_flag_repository(notification)
|
74
|
+
fetch_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_SEGMENT'), @feature_flags_repository)
|
75
|
+
if fetch_rule_based_segments_if_not_exists(Helpers::Util.segment_names_by_object(new_split, 'IN_RULE_BASED_SEGMENT'),
|
76
|
+
notification.data['changeNumber'])
|
77
|
+
return true
|
78
|
+
end
|
73
79
|
|
74
80
|
@telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS)
|
75
81
|
|
@@ -80,30 +86,63 @@ module SplitIoClient
|
|
80
86
|
false
|
81
87
|
end
|
82
88
|
|
89
|
+
def update_feature_flag_repository(notification)
|
90
|
+
new_split = return_object_from_json(notification)
|
91
|
+
SplitIoClient::Helpers::RepositoryHelper.update_feature_flag_repository(@feature_flags_repository, [new_split],
|
92
|
+
notification.data['changeNumber'], @config, false)
|
93
|
+
new_split
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_rule_based_segment(notification)
|
97
|
+
return true if @rule_based_segment_repository.get_change_number.to_i >= notification.data['changeNumber']
|
98
|
+
return false unless !notification.data['d'].nil? &&
|
99
|
+
@rule_based_segment_repository.get_change_number == notification.data['pcn']
|
100
|
+
|
101
|
+
new_rb_segment = return_object_from_json(notification)
|
102
|
+
SplitIoClient::Helpers::RepositoryHelper.update_rule_based_segment_repository(@rule_based_segment_repository,
|
103
|
+
[new_rb_segment],
|
104
|
+
notification.data['changeNumber'], @config)
|
105
|
+
fetch_segments_if_not_exists(Helpers::Util.segment_names_in_rb_segment(new_rb_segment, 'IN_SEGMENT'),
|
106
|
+
@rule_based_segment_repository)
|
107
|
+
|
108
|
+
# @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS)
|
109
|
+
|
110
|
+
true
|
111
|
+
rescue StandardError => e
|
112
|
+
@config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled
|
113
|
+
|
114
|
+
false
|
115
|
+
end
|
116
|
+
|
83
117
|
def kill_feature_flag(notification)
|
84
118
|
return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber']
|
85
119
|
|
86
120
|
@config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}")
|
87
|
-
@feature_flags_repository.kill(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
)
|
92
|
-
@synchronizer.fetch_splits(notification.data['changeNumber'])
|
121
|
+
@feature_flags_repository.kill(notification.data['changeNumber'],
|
122
|
+
notification.data['splitName'],
|
123
|
+
notification.data['defaultTreatment'])
|
124
|
+
@synchronizer.fetch_splits(notification.data['changeNumber'], 0)
|
93
125
|
end
|
94
126
|
|
95
|
-
def
|
96
|
-
|
97
|
-
JSON.parse(
|
127
|
+
def return_object_from_json(notification)
|
128
|
+
object_json = Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d'])
|
129
|
+
JSON.parse(object_json, symbolize_names: true)
|
98
130
|
end
|
99
131
|
|
100
|
-
def fetch_segments_if_not_exists(
|
101
|
-
segment_names = Helpers::Util.segment_names_by_feature_flag(feature_flag)
|
132
|
+
def fetch_segments_if_not_exists(segment_names, object_repository)
|
102
133
|
return if segment_names.nil?
|
103
134
|
|
104
|
-
|
135
|
+
object_repository.set_segment_names(segment_names)
|
105
136
|
@segment_fetcher.fetch_segments_if_not_exists(segment_names)
|
106
137
|
end
|
138
|
+
|
139
|
+
def fetch_rule_based_segments_if_not_exists(segment_names, change_number)
|
140
|
+
return false if segment_names.nil? || segment_names.empty? || @rule_based_segment_repository.contains?(segment_names.to_a)
|
141
|
+
|
142
|
+
@synchronizer.fetch_splits(0, change_number)
|
143
|
+
|
144
|
+
true
|
145
|
+
end
|
107
146
|
end
|
108
147
|
end
|
109
148
|
end
|
data/lib/splitclient-rb.rb
CHANGED
@@ -23,6 +23,7 @@ require 'splitclient-rb/cache/repositories/segments_repository'
|
|
23
23
|
require 'splitclient-rb/cache/repositories/splits_repository'
|
24
24
|
require 'splitclient-rb/cache/repositories/events_repository'
|
25
25
|
require 'splitclient-rb/cache/repositories/impressions_repository'
|
26
|
+
require 'splitclient-rb/cache/repositories/rule_based_segments_repository'
|
26
27
|
require 'splitclient-rb/cache/repositories/events/memory_repository'
|
27
28
|
require 'splitclient-rb/cache/repositories/events/redis_repository'
|
28
29
|
require 'splitclient-rb/cache/repositories/flag_sets/memory_repository'
|
@@ -47,6 +48,7 @@ require 'splitclient-rb/helpers/thread_helper'
|
|
47
48
|
require 'splitclient-rb/helpers/decryption_helper'
|
48
49
|
require 'splitclient-rb/helpers/util'
|
49
50
|
require 'splitclient-rb/helpers/repository_helper'
|
51
|
+
require 'splitclient-rb/helpers/evaluator_helper'
|
50
52
|
require 'splitclient-rb/split_factory'
|
51
53
|
require 'splitclient-rb/split_factory_builder'
|
52
54
|
require 'splitclient-rb/split_config'
|
@@ -96,13 +98,17 @@ require 'splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher'
|
|
96
98
|
require 'splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher'
|
97
99
|
require 'splitclient-rb/engine/matchers/between_semver_matcher'
|
98
100
|
require 'splitclient-rb/engine/matchers/in_list_semver_matcher'
|
101
|
+
require 'splitclient-rb/engine/matchers/rule_based_segment_matcher'
|
102
|
+
require 'splitclient-rb/engine/matchers/prerequisites_matcher'
|
99
103
|
require 'splitclient-rb/engine/evaluator/splitter'
|
100
104
|
require 'splitclient-rb/engine/impressions/noop_unique_keys_tracker'
|
101
105
|
require 'splitclient-rb/engine/impressions/unique_keys_tracker'
|
102
106
|
require 'splitclient-rb/engine/metrics/binary_search_latency_tracker'
|
103
107
|
require 'splitclient-rb/engine/models/split'
|
104
108
|
require 'splitclient-rb/engine/models/label'
|
109
|
+
require 'splitclient-rb/engine/models/segment_type'
|
105
110
|
require 'splitclient-rb/engine/models/treatment'
|
111
|
+
require 'splitclient-rb/engine/models/split_http_response'
|
106
112
|
require 'splitclient-rb/engine/auth_api_client'
|
107
113
|
require 'splitclient-rb/engine/back_off'
|
108
114
|
require 'splitclient-rb/engine/push_manager'
|
data/splitclient-rb.gemspec
CHANGED
@@ -47,8 +47,8 @@ Gem::Specification.new do |spec|
|
|
47
47
|
spec.add_development_dependency 'simplecov', '~> 0.20'
|
48
48
|
spec.add_development_dependency 'simplecov-json', '~> 0.2'
|
49
49
|
spec.add_development_dependency 'timecop', '~> 0.9'
|
50
|
-
spec.add_development_dependency 'webmock', '~> 3.
|
51
|
-
spec.add_development_dependency 'webrick', '~> 1.
|
50
|
+
spec.add_development_dependency 'webmock', '~> 3.24'
|
51
|
+
spec.add_development_dependency 'webrick', '~> 1.8.2'
|
52
52
|
|
53
53
|
spec.add_runtime_dependency 'bitarray', '~> 1.3'
|
54
54
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|