splitclient-rb 8.4.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +9 -2
- data/CHANGES.txt +24 -0
- data/LICENSE +169 -13
- data/NOTICE.txt +5 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +9 -7
- data/lib/splitclient-rb/cache/filter/bloom_filter.rb +10 -6
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +1 -0
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +21 -2
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +42 -12
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +24 -10
- data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +2 -1
- data/lib/splitclient-rb/clients/split_client.rb +146 -62
- data/lib/splitclient-rb/engine/api/client.rb +8 -0
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
- data/lib/splitclient-rb/engine/api/splits.rb +100 -24
- data/lib/splitclient-rb/engine/auth_api_client.rb +3 -3
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +56 -30
- 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/unique_keys_tracker.rb +58 -11
- 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 +78 -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 +1 -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 +14 -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/models/valid_sdk_event.rb +14 -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/status_manager.rb +7 -1
- data/lib/splitclient-rb/engine/sync_manager.rb +6 -6
- data/lib/splitclient-rb/engine/synchronizer.rb +37 -17
- data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +39 -1
- data/lib/splitclient-rb/helpers/util.rb +12 -3
- data/lib/splitclient-rb/managers/split_manager.rb +2 -1
- data/lib/splitclient-rb/spec.rb +1 -1
- data/lib/splitclient-rb/split_config.rb +45 -5
- data/lib/splitclient-rb/split_factory.rb +27 -21
- data/lib/splitclient-rb/sse/event_source/client.rb +86 -29
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +2 -2
- data/lib/splitclient-rb/sse/event_source/event_types.rb +1 -0
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +3 -3
- data/lib/splitclient-rb/sse/notification_processor.rb +3 -1
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +4 -4
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +63 -24
- data/lib/splitclient-rb/utilitites.rb +6 -10
- data/lib/splitclient-rb/validators.rb +56 -25
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +22 -0
- data/sonar-project.properties +1 -0
- data/splitclient-rb.gemspec +3 -4
- metadata +32 -38
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
class FallbackTreatmentCalculator
|
|
6
|
+
attr_accessor :fallback_treatments_configuration, :label_prefix
|
|
7
|
+
|
|
8
|
+
def initialize(fallback_treatment_configuration)
|
|
9
|
+
@label_prefix = 'fallback - '
|
|
10
|
+
@fallback_treatments_configuration = fallback_treatment_configuration
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resolve(flag_name, label)
|
|
14
|
+
default_fallback_treatment = Engine::Models::FallbackTreatment.new(
|
|
15
|
+
Engine::Models::Treatment::CONTROL,
|
|
16
|
+
nil,
|
|
17
|
+
label
|
|
18
|
+
)
|
|
19
|
+
return default_fallback_treatment if @fallback_treatments_configuration.nil?
|
|
20
|
+
|
|
21
|
+
if !@fallback_treatments_configuration.by_flag_fallback_treatment.nil? \
|
|
22
|
+
&& !@fallback_treatments_configuration.by_flag_fallback_treatment.fetch(flag_name, nil).nil?
|
|
23
|
+
return copy_with_label(
|
|
24
|
+
@fallback_treatments_configuration.by_flag_fallback_treatment[flag_name],
|
|
25
|
+
resolve_label(label)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
return copy_with_label(@fallback_treatments_configuration.global_fallback_treatment, resolve_label(label)) \
|
|
30
|
+
unless @fallback_treatments_configuration.global_fallback_treatment.nil?
|
|
31
|
+
|
|
32
|
+
default_fallback_treatment
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def resolve_label(label)
|
|
38
|
+
return nil if label.nil?
|
|
39
|
+
|
|
40
|
+
@label_prefix + label
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def copy_with_label(fallback_treatment, label)
|
|
44
|
+
Engine::Models::FallbackTreatment.new(fallback_treatment.treatment, fallback_treatment.config, label)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -14,9 +14,9 @@ module SplitIoClient
|
|
|
14
14
|
@filter_adapter = filter_adapter
|
|
15
15
|
@sender_adapter = sender_adapter
|
|
16
16
|
@cache = cache
|
|
17
|
-
@cache_max_size = config.unique_keys_cache_max_size
|
|
18
17
|
@max_bulk_size = config.unique_keys_bulk_size
|
|
19
18
|
@semaphore = Mutex.new
|
|
19
|
+
@keys_size = 0
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def call
|
|
@@ -30,8 +30,9 @@ module SplitIoClient
|
|
|
30
30
|
@filter_adapter.add(feature_name, key)
|
|
31
31
|
|
|
32
32
|
add_or_update(feature_name, key)
|
|
33
|
+
@keys_size += 1
|
|
33
34
|
|
|
34
|
-
send_bulk_data if @
|
|
35
|
+
send_bulk_data if @keys_size >= @max_bulk_size
|
|
35
36
|
|
|
36
37
|
true
|
|
37
38
|
rescue StandardError => e
|
|
@@ -70,27 +71,73 @@ module SplitIoClient
|
|
|
70
71
|
end
|
|
71
72
|
end
|
|
72
73
|
|
|
74
|
+
def clear_cache
|
|
75
|
+
uniques = @cache.clone
|
|
76
|
+
keys_size = @keys_size
|
|
77
|
+
@cache.clear
|
|
78
|
+
@keys_size = 0
|
|
79
|
+
|
|
80
|
+
[uniques, keys_size]
|
|
81
|
+
end
|
|
82
|
+
|
|
73
83
|
def send_bulk_data
|
|
74
84
|
@semaphore.synchronize do
|
|
75
85
|
return if @cache.empty?
|
|
76
86
|
|
|
77
|
-
uniques =
|
|
78
|
-
@
|
|
79
|
-
|
|
80
|
-
if uniques.size <= @max_bulk_size
|
|
87
|
+
uniques, keys_size = clear_cache
|
|
88
|
+
if keys_size <= @max_bulk_size
|
|
81
89
|
@sender_adapter.record_uniques_key(uniques)
|
|
82
90
|
return
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
bulks = SplitIoClient::Utilities.split_bulk_to_send(uniques, uniques.size / @max_bulk_size)
|
|
86
91
|
|
|
87
|
-
bulks.each do |b|
|
|
88
|
-
@sender_adapter.record_uniques_key(b)
|
|
89
92
|
end
|
|
93
|
+
bulks = flatten_bulks(uniques)
|
|
94
|
+
bulks_to_post = group_bulks_by_max_size(bulks)
|
|
95
|
+
@sender_adapter.record_uniques_key(bulks_to_post)
|
|
90
96
|
end
|
|
91
97
|
rescue StandardError => e
|
|
92
98
|
@config.log_found_exception(__method__.to_s, e)
|
|
93
99
|
end
|
|
100
|
+
|
|
101
|
+
def group_bulks_by_max_size(bulks)
|
|
102
|
+
current_size = 0
|
|
103
|
+
bulks_to_post = Concurrent::Hash.new
|
|
104
|
+
bulks.each do |bulk|
|
|
105
|
+
key, value = bulk.first
|
|
106
|
+
if (value.size + current_size) > @max_bulk_size
|
|
107
|
+
@sender_adapter.record_uniques_key(bulks_to_post)
|
|
108
|
+
bulks_to_post = Concurrent::Hash.new
|
|
109
|
+
current_size = 0
|
|
110
|
+
end
|
|
111
|
+
bulks_to_post[key] = value
|
|
112
|
+
current_size += value.size
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
bulks_to_post
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def flatten_bulks(uniques)
|
|
119
|
+
bulks = []
|
|
120
|
+
uniques.each_key do |unique_key|
|
|
121
|
+
bulks += check_keys_and_split_to_bulks(uniques[unique_key], unique_key)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
bulks
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def check_keys_and_split_to_bulks(value, key)
|
|
128
|
+
unique_updated = []
|
|
129
|
+
if value.size > @max_bulk_size
|
|
130
|
+
sub_bulks = SplitIoClient::Utilities.split_bulk_to_send(value, @max_bulk_size)
|
|
131
|
+
sub_bulks.each do |sub_bulk|
|
|
132
|
+
unique_updated << { key => sub_bulk.to_set }
|
|
133
|
+
end
|
|
134
|
+
return unique_updated
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
unique_updated << { key => value }
|
|
138
|
+
|
|
139
|
+
unique_updated
|
|
140
|
+
end
|
|
94
141
|
end
|
|
95
142
|
end
|
|
96
143
|
end
|
|
@@ -56,7 +56,9 @@ module SplitIoClient
|
|
|
56
56
|
|
|
57
57
|
@matchers.all? do |matcher|
|
|
58
58
|
if match_with_key?(matcher)
|
|
59
|
-
|
|
59
|
+
key = args[:value]
|
|
60
|
+
key = args[:matching_key] unless args[:matching_key].nil?
|
|
61
|
+
matcher.match?(value: key)
|
|
60
62
|
else
|
|
61
63
|
matcher.match?(args)
|
|
62
64
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
class PrerequisitesMatcher
|
|
5
|
+
def initialize(prerequisites, logger)
|
|
6
|
+
@prerequisites = prerequisites
|
|
7
|
+
@logger = logger
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def match?(args)
|
|
11
|
+
keys = { matching_key: args[:matching_key], bucketing_key: args[:bucketing_key] }
|
|
12
|
+
|
|
13
|
+
match = true
|
|
14
|
+
@prerequisites.each do |prerequisite|
|
|
15
|
+
evaluate = args[:evaluator].evaluate_feature_flag(keys, prerequisite[:n], args[:attributes])
|
|
16
|
+
next if prerequisite[:ts].include?(evaluate[:treatment])
|
|
17
|
+
|
|
18
|
+
@logger.log_if_debug("[PrerequisitesMatcher] feature flag #{prerequisite[:n]} evaluated to #{evaluate[:treatment]} \
|
|
19
|
+
that does not exist in prerequisited treatments.")
|
|
20
|
+
match = false
|
|
21
|
+
break
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
match
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def string_type?
|
|
28
|
+
false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
#
|
|
5
|
+
# class to implement the user defined matcher
|
|
6
|
+
#
|
|
7
|
+
class RuleBasedSegmentMatcher < Matcher
|
|
8
|
+
MATCHER_TYPE = 'IN_RULE_BASED_SEGMENT'
|
|
9
|
+
|
|
10
|
+
def initialize(segments_repository, rule_based_segments_repository, segment_name, config)
|
|
11
|
+
super(config.logger)
|
|
12
|
+
@rule_based_segments_repository = rule_based_segments_repository
|
|
13
|
+
@segments_repository = segments_repository
|
|
14
|
+
@segment_name = segment_name
|
|
15
|
+
@config = config
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# evaluates if the key matches the matcher
|
|
20
|
+
#
|
|
21
|
+
# @param key [string] key value to be matched
|
|
22
|
+
#
|
|
23
|
+
# @return [boolean] evaluation of the key against the segment
|
|
24
|
+
def match?(args)
|
|
25
|
+
rule_based_segment = @rule_based_segments_repository.get_rule_based_segment(@segment_name)
|
|
26
|
+
return false if rule_based_segment.nil?
|
|
27
|
+
|
|
28
|
+
key = update_key(args)
|
|
29
|
+
return false if rule_based_segment[:excluded][:keys].include?(key)
|
|
30
|
+
|
|
31
|
+
return false unless check_excluded_segments(rule_based_segment, key, args)
|
|
32
|
+
|
|
33
|
+
matched = false
|
|
34
|
+
rule_based_segment[:conditions].each do |c|
|
|
35
|
+
condition = SplitIoClient::Condition.new(c, @config)
|
|
36
|
+
next if condition.empty?
|
|
37
|
+
|
|
38
|
+
matched = Helpers::EvaluatorHelper.matcher_type(condition, @segments_repository, @rule_based_segments_repository).match?(args)
|
|
39
|
+
|
|
40
|
+
break if matched
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@logger.debug("[InRuleSegmentMatcher] #{@segment_name} is in rule based segment -> #{matched}")
|
|
44
|
+
matched
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def check_excluded_segments(rule_based_segment, key, args)
|
|
50
|
+
rule_based_segment[:excluded][:segments].each do |segment|
|
|
51
|
+
if segment[:type] == SplitIoClient::Engine::Models::SegmentType::STANDARD &&
|
|
52
|
+
@segments_repository.in_segment?(segment[:name], key)
|
|
53
|
+
return false
|
|
54
|
+
end
|
|
55
|
+
return false if segment[:type] == SplitIoClient::Engine::Models::SegmentType::RULE_BASED_SEGMENT && match_rbs(
|
|
56
|
+
@rule_based_segments_repository.get_rule_based_segment(segment[:name]), args
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def update_key(args)
|
|
63
|
+
if args[:value].nil? || args[:value].empty?
|
|
64
|
+
args[:matching_key]
|
|
65
|
+
else
|
|
66
|
+
args[:value]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def match_rbs(rule_based_segment, args)
|
|
71
|
+
rbs_matcher = RuleBasedSegmentMatcher.new(@segments_repository, @rule_based_segments_repository,
|
|
72
|
+
rule_based_segment[:name], @config)
|
|
73
|
+
rbs_matcher.match?(matching_key: args[:matching_key],
|
|
74
|
+
bucketing_key: args[:value],
|
|
75
|
+
attributes: args[:attributes])
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine::Models
|
|
5
|
+
class EventActiveSubscriptions
|
|
6
|
+
attr_accessor :triggered, :handler
|
|
7
|
+
|
|
8
|
+
def initialize(triggered, handler)
|
|
9
|
+
@triggered = triggered
|
|
10
|
+
@handler = handler
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module SplitIoClient::Engine::Models
|
|
2
|
+
class FallbackTreatmentsConfiguration
|
|
3
|
+
attr_accessor :global_fallback_treatment, :by_flag_fallback_treatment
|
|
4
|
+
|
|
5
|
+
def initialize(global_fallback_treatment=nil, by_flag_fallback_treatment=nil)
|
|
6
|
+
@global_fallback_treatment = build_global_fallback_treatment(global_fallback_treatment)
|
|
7
|
+
@by_flag_fallback_treatment = build_by_flag_fallback_treatment(by_flag_fallback_treatment)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def build_global_fallback_treatment(global_fallback_treatment)
|
|
13
|
+
if global_fallback_treatment.is_a? String
|
|
14
|
+
return FallbackTreatment.new(global_fallback_treatment)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
global_fallback_treatment
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def build_by_flag_fallback_treatment(by_flag_fallback_treatment)
|
|
21
|
+
return nil unless by_flag_fallback_treatment.is_a?(Hash)
|
|
22
|
+
processed_by_flag_fallback_treatment = Hash.new
|
|
23
|
+
|
|
24
|
+
by_flag_fallback_treatment.each do |key, value|
|
|
25
|
+
if value.is_a? String
|
|
26
|
+
processed_by_flag_fallback_treatment[key] = FallbackTreatment.new(value)
|
|
27
|
+
next
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
processed_by_flag_fallback_treatment[key] = value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
processed_by_flag_fallback_treatment
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class SplitIoClient::Engine::Models::SdkInternalEvent
|
|
2
|
+
SDK_READY = 'SDK_READY'
|
|
3
|
+
FLAGS_UPDATED = 'FLAGS_UPDATED'
|
|
4
|
+
FLAG_KILLED_NOTIFICATION = 'FLAG_KILLED_NOTIFICATION'
|
|
5
|
+
SEGMENTS_UPDATED = 'SEGMENTS_UPDATED'
|
|
6
|
+
RB_SEGMENTS_UPDATED = 'RB_SEGMENTS_UPDATED'
|
|
7
|
+
LARGE_SEGMENTS_UPDATED = 'LARGE_SEGMENTS_UPDATED'
|
|
8
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine::Models
|
|
5
|
+
class SdkInternalEventNotification
|
|
6
|
+
attr_reader :internal_event, :metadata
|
|
7
|
+
|
|
8
|
+
def initialize(internal_event, metadata)
|
|
9
|
+
@internal_event = internal_event
|
|
10
|
+
@metadata = metadata
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module SplitIoClient
|
|
2
|
+
module Engine
|
|
3
|
+
module Models
|
|
4
|
+
class SplitHttpResponse
|
|
5
|
+
attr_accessor :status, :body
|
|
6
|
+
|
|
7
|
+
def initialize(status, body, success)
|
|
8
|
+
@status = status
|
|
9
|
+
@body = body
|
|
10
|
+
@success = success
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def success?
|
|
14
|
+
@success
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -230,6 +230,13 @@ module SplitIoClient
|
|
|
230
230
|
)
|
|
231
231
|
end
|
|
232
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
|
+
|
|
233
240
|
#
|
|
234
241
|
# @return [object] the negate value for this condition
|
|
235
242
|
def negate
|
|
@@ -246,6 +253,8 @@ module SplitIoClient
|
|
|
246
253
|
# @return [void]
|
|
247
254
|
def set_partitions
|
|
248
255
|
partitions_list = []
|
|
256
|
+
return partitions_list unless @data.key?(:partitions) or @data.key?('partitions')
|
|
257
|
+
|
|
249
258
|
@data[:partitions].each do |p|
|
|
250
259
|
partition = SplitIoClient::Partition.new(p)
|
|
251
260
|
partitions_list << partition
|
|
@@ -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
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
module SplitIoClient
|
|
4
4
|
module Engine
|
|
5
5
|
class StatusManager
|
|
6
|
-
def initialize(config)
|
|
6
|
+
def initialize(config, internal_events_queue)
|
|
7
7
|
@config = config
|
|
8
8
|
@sdk_ready = Concurrent::CountDownLatch.new(1)
|
|
9
|
+
@internal_events_queue = internal_events_queue
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def ready?
|
|
@@ -19,6 +20,11 @@ module SplitIoClient
|
|
|
19
20
|
|
|
20
21
|
@sdk_ready.count_down
|
|
21
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
|
+
)
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def wait_until_ready(seconds = nil)
|
|
@@ -47,13 +47,13 @@ module SplitIoClient
|
|
|
47
47
|
connected = false
|
|
48
48
|
|
|
49
49
|
if @config.streaming_enabled
|
|
50
|
-
@config.logger.debug('Starting Streaming mode ...')
|
|
50
|
+
@config.logger.debug('Starting Streaming mode ...') if @config.debug_enabled
|
|
51
51
|
start_push_status_monitor
|
|
52
52
|
connected = @push_manager.start_sse
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
unless connected
|
|
56
|
-
@config.logger.debug('Starting Polling mode ...')
|
|
56
|
+
@config.logger.debug('Starting Polling mode ...') if @config.debug_enabled
|
|
57
57
|
@synchronizer.start_periodic_fetch
|
|
58
58
|
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
59
59
|
end
|
|
@@ -92,7 +92,7 @@ module SplitIoClient
|
|
|
92
92
|
|
|
93
93
|
def process_connected
|
|
94
94
|
if @sse_connected.value
|
|
95
|
-
@config.logger.debug('Streaming already connected.')
|
|
95
|
+
@config.logger.debug('Streaming already connected.') if @config.debug_enabled
|
|
96
96
|
return
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -107,7 +107,7 @@ module SplitIoClient
|
|
|
107
107
|
|
|
108
108
|
def process_forced_stop
|
|
109
109
|
unless @sse_connected.value
|
|
110
|
-
@config.logger.debug('Streaming already disconnected.')
|
|
110
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
111
111
|
return
|
|
112
112
|
end
|
|
113
113
|
|
|
@@ -120,7 +120,7 @@ module SplitIoClient
|
|
|
120
120
|
|
|
121
121
|
def process_disconnect(reconnect)
|
|
122
122
|
unless @sse_connected.value
|
|
123
|
-
@config.logger.debug('Streaming already disconnected.')
|
|
123
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
124
124
|
return
|
|
125
125
|
end
|
|
126
126
|
|
|
@@ -169,7 +169,7 @@ module SplitIoClient
|
|
|
169
169
|
when Constants::PUSH_SUBSYSTEM_OFF
|
|
170
170
|
process_push_shutdown
|
|
171
171
|
else
|
|
172
|
-
@config.logger.debug('Incorrect push status type.')
|
|
172
|
+
@config.logger.debug('Incorrect push status type.') if @config.debug_enabled
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
rescue StandardError => e
|