splitclient-rb 6.4.1 → 7.0.0.pre.rc1
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/Detailed-README.md +9 -21
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +5 -4
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +4 -3
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +10 -9
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +7 -6
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +5 -4
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +9 -8
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +3 -2
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +5 -4
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +6 -4
- data/lib/splitclient-rb/cache/repositories/repository.rb +7 -2
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +6 -5
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +54 -7
- data/lib/splitclient-rb/cache/routers/impression_router.rb +5 -4
- data/lib/splitclient-rb/cache/senders/events_sender.rb +7 -6
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +10 -9
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +9 -8
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +19 -10
- data/lib/splitclient-rb/cache/stores/segment_store.rb +15 -28
- data/lib/splitclient-rb/cache/stores/split_store.rb +13 -15
- data/lib/splitclient-rb/clients/localhost_split_client.rb +8 -7
- data/lib/splitclient-rb/clients/split_client.rb +65 -35
- data/lib/splitclient-rb/engine/api/client.rb +17 -13
- data/lib/splitclient-rb/engine/api/events.rb +7 -6
- data/lib/splitclient-rb/engine/api/impressions.rb +6 -5
- data/lib/splitclient-rb/engine/api/metrics.rb +8 -7
- data/lib/splitclient-rb/engine/api/segments.rb +11 -10
- data/lib/splitclient-rb/engine/api/splits.rb +6 -5
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +5 -4
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +4 -4
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +3 -3
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +3 -3
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/matcher.rb +4 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +4 -4
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/models/label.rb +2 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +31 -20
- data/lib/splitclient-rb/engine/parser/evaluator.rb +3 -2
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +9 -7
- data/lib/splitclient-rb/localhost_split_factory.rb +3 -2
- data/lib/splitclient-rb/managers/split_manager.rb +39 -5
- data/lib/splitclient-rb/redis_metrics_fixer.rb +5 -4
- data/lib/splitclient-rb/split_config.rb +35 -14
- data/lib/splitclient-rb/split_factory.rb +44 -32
- data/lib/splitclient-rb/split_factory_builder.rb +4 -5
- data/lib/splitclient-rb/split_factory_registry.rb +51 -0
- data/lib/splitclient-rb/split_logger.rb +5 -14
- data/lib/splitclient-rb/validators.rb +19 -16
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +2 -1
- metadata +5 -4
@@ -4,9 +4,10 @@ module SplitIoClient
|
|
4
4
|
module Cache
|
5
5
|
module Senders
|
6
6
|
class MetricsSender
|
7
|
-
def initialize(metrics_repository, api_key)
|
7
|
+
def initialize(metrics_repository, api_key, config)
|
8
8
|
@metrics_repository = metrics_repository
|
9
9
|
@api_key = api_key
|
10
|
+
@config = config
|
10
11
|
end
|
11
12
|
|
12
13
|
def call
|
@@ -24,19 +25,19 @@ module SplitIoClient
|
|
24
25
|
private
|
25
26
|
|
26
27
|
def metrics_thread
|
27
|
-
|
28
|
+
@config.threads[:metrics_sender] = Thread.new do
|
28
29
|
begin
|
29
|
-
|
30
|
-
|
30
|
+
@config.logger.info('Starting metrics service')
|
31
|
+
|
31
32
|
loop do
|
32
33
|
post_metrics
|
33
34
|
|
34
|
-
sleep(SplitIoClient::Utilities.randomize_interval(
|
35
|
+
sleep(SplitIoClient::Utilities.randomize_interval(@config.metrics_refresh_rate))
|
35
36
|
end
|
36
37
|
rescue SplitIoClient::SDKShutdownException
|
37
38
|
post_metrics
|
38
39
|
|
39
|
-
|
40
|
+
@config.logger.info('Posting metrics due to shutdown')
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
@@ -44,11 +45,11 @@ module SplitIoClient
|
|
44
45
|
def post_metrics
|
45
46
|
metrics_api.post
|
46
47
|
rescue StandardError => error
|
47
|
-
|
48
|
+
@config.log_found_exception(__method__.to_s, error)
|
48
49
|
end
|
49
50
|
|
50
51
|
def metrics_api
|
51
|
-
@metrics_api ||= SplitIoClient::Api::Metrics.new(@api_key, @metrics_repository)
|
52
|
+
@metrics_api ||= SplitIoClient::Api::Metrics.new(@api_key, @metrics_repository, @config)
|
52
53
|
end
|
53
54
|
end
|
54
55
|
end
|
@@ -7,37 +7,46 @@ module SplitIoClient
|
|
7
7
|
class SDKBlocker
|
8
8
|
attr_reader :splits_repository
|
9
9
|
|
10
|
-
def initialize(splits_repository, segments_repository)
|
10
|
+
def initialize(splits_repository, segments_repository, config)
|
11
11
|
@splits_repository = splits_repository
|
12
12
|
@segments_repository = segments_repository
|
13
|
+
@config = config
|
13
14
|
|
14
|
-
@
|
15
|
-
|
15
|
+
if @config.standalone?
|
16
|
+
@splits_repository.not_ready!
|
17
|
+
@segments_repository.not_ready!
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
21
|
def splits_ready!
|
19
|
-
|
22
|
+
if !ready?
|
23
|
+
@splits_repository.ready!
|
24
|
+
@config.logger.info('splits are ready')
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
def segments_ready!
|
23
|
-
|
29
|
+
if !ready?
|
30
|
+
@segments_repository.ready!
|
31
|
+
@config.logger.info('segments are ready')
|
32
|
+
end
|
24
33
|
end
|
25
34
|
|
26
|
-
def block
|
35
|
+
def block(time = nil)
|
27
36
|
begin
|
28
|
-
|
37
|
+
timeout = time || @config.block_until_ready
|
38
|
+
Timeout::timeout(timeout) do
|
29
39
|
sleep 0.1 until ready?
|
30
40
|
end
|
31
41
|
rescue Timeout::Error
|
32
42
|
fail SDKBlockerTimeoutExpiredException, 'SDK start up timeout expired'
|
33
43
|
end
|
34
44
|
|
35
|
-
|
36
|
-
SplitIoClient.configuration.threads[:split_store].run
|
37
|
-
SplitIoClient.configuration.threads[:segment_store].run
|
45
|
+
@config.logger.info('SplitIO SDK is ready')
|
38
46
|
end
|
39
47
|
|
40
48
|
def ready?
|
49
|
+
return true if @config.consumer?
|
41
50
|
@splits_repository.ready? && @segments_repository.ready?
|
42
51
|
end
|
43
52
|
end
|
@@ -4,10 +4,11 @@ module SplitIoClient
|
|
4
4
|
class SegmentStore
|
5
5
|
attr_reader :segments_repository
|
6
6
|
|
7
|
-
def initialize(segments_repository, api_key, metrics, sdk_blocker = nil)
|
7
|
+
def initialize(segments_repository, api_key, metrics, config, sdk_blocker = nil)
|
8
8
|
@segments_repository = segments_repository
|
9
9
|
@api_key = api_key
|
10
10
|
@metrics = metrics
|
11
|
+
@config = config
|
11
12
|
@sdk_blocker = sdk_blocker
|
12
13
|
end
|
13
14
|
|
@@ -28,42 +29,28 @@ module SplitIoClient
|
|
28
29
|
private
|
29
30
|
|
30
31
|
def segments_thread
|
31
|
-
|
32
|
-
|
33
|
-
SplitIoClient.configuration.block_until_ready > 0 ? blocked_store : unblocked_store
|
34
|
-
end
|
35
|
-
end
|
32
|
+
@config.threads[:segment_store] = Thread.new do
|
33
|
+
@config.logger.info('Starting segments fetcher service')
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
next unless @sdk_blocker.splits_repository.ready?
|
35
|
+
loop do
|
36
|
+
next unless @sdk_blocker.splits_repository.ready?
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
store_segments
|
39
|
+
@config.logger.debug("Segment names: #{@segments_repository.used_segment_names.to_a}") if @config.debug_enabled
|
43
40
|
|
44
|
-
|
45
|
-
@
|
46
|
-
|
41
|
+
sleep_for = random_interval(@config.segments_refresh_rate)
|
42
|
+
@config.logger.debug("Segments store is sleeping for: #{sleep_for} seconds") if @config.debug_enabled
|
43
|
+
sleep(sleep_for)
|
47
44
|
end
|
48
|
-
|
49
|
-
sleep_for = random_interval(SplitIoClient.configuration.segments_refresh_rate)
|
50
|
-
SplitIoClient.configuration.logger.debug("Segments store is sleeping for: #{sleep_for} seconds") if SplitIoClient.configuration.debug_enabled
|
51
|
-
sleep(sleep_for)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def unblocked_store
|
56
|
-
loop do
|
57
|
-
store_segments
|
58
|
-
|
59
|
-
sleep(random_interval(SplitIoClient.configuration.segments_refresh_rate))
|
60
45
|
end
|
61
46
|
end
|
62
47
|
|
63
48
|
def store_segments
|
64
49
|
segments_api.store_segments_by_names(@segments_repository.used_segment_names)
|
50
|
+
|
51
|
+
@sdk_blocker.segments_ready!
|
65
52
|
rescue StandardError => error
|
66
|
-
|
53
|
+
@config.log_found_exception(__method__.to_s, error)
|
67
54
|
end
|
68
55
|
|
69
56
|
def random_interval(interval)
|
@@ -73,7 +60,7 @@ module SplitIoClient
|
|
73
60
|
end
|
74
61
|
|
75
62
|
def segments_api
|
76
|
-
@segments_api ||= SplitIoClient::Api::Segments.new(@api_key, @metrics, @segments_repository)
|
63
|
+
@segments_api ||= SplitIoClient::Api::Segments.new(@api_key, @metrics, @segments_repository, @config)
|
77
64
|
end
|
78
65
|
end
|
79
66
|
end
|
@@ -4,10 +4,11 @@ module SplitIoClient
|
|
4
4
|
class SplitStore
|
5
5
|
attr_reader :splits_repository
|
6
6
|
|
7
|
-
def initialize(splits_repository, api_key, metrics, sdk_blocker = nil)
|
7
|
+
def initialize(splits_repository, api_key, metrics, config, sdk_blocker = nil)
|
8
8
|
@splits_repository = splits_repository
|
9
9
|
@api_key = api_key
|
10
10
|
@metrics = metrics
|
11
|
+
@config = config
|
11
12
|
@sdk_blocker = sdk_blocker
|
12
13
|
end
|
13
14
|
|
@@ -28,12 +29,12 @@ module SplitIoClient
|
|
28
29
|
private
|
29
30
|
|
30
31
|
def splits_thread
|
31
|
-
|
32
|
-
|
32
|
+
@config.threads[:split_store] = Thread.new do
|
33
|
+
@config.logger.info('Starting splits fetcher service')
|
33
34
|
loop do
|
34
35
|
store_splits
|
35
36
|
|
36
|
-
sleep(random_interval(
|
37
|
+
sleep(random_interval(@config.features_refresh_rate))
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -48,15 +49,12 @@ module SplitIoClient
|
|
48
49
|
@splits_repository.set_segment_names(data[:segment_names])
|
49
50
|
@splits_repository.set_change_number(data[:till])
|
50
51
|
|
51
|
-
|
52
|
+
@config.logger.debug("segments seen(#{data[:segment_names].length}): #{data[:segment_names].to_a}") if @config.debug_enabled
|
52
53
|
|
53
|
-
|
54
|
-
@sdk_blocker.splits_ready!
|
55
|
-
SplitIoClient.configuration.logger.info('splits are ready')
|
56
|
-
end
|
54
|
+
@sdk_blocker.splits_ready!
|
57
55
|
|
58
56
|
rescue StandardError => error
|
59
|
-
|
57
|
+
@config.log_found_exception(__method__.to_s, error)
|
60
58
|
end
|
61
59
|
|
62
60
|
def random_interval(interval)
|
@@ -71,7 +69,7 @@ module SplitIoClient
|
|
71
69
|
|
72
70
|
def add_split_unless_archived(split)
|
73
71
|
if Engine::Models::Split.archived?(split)
|
74
|
-
|
72
|
+
@config.logger.debug("Seeing archived split #{split[:name]}") if @config.debug_enabled
|
75
73
|
|
76
74
|
remove_archived_split(split)
|
77
75
|
else
|
@@ -80,13 +78,13 @@ module SplitIoClient
|
|
80
78
|
end
|
81
79
|
|
82
80
|
def remove_archived_split(split)
|
83
|
-
|
81
|
+
@config.logger.debug("removing split from store(#{split})") if @config.debug_enabled
|
84
82
|
|
85
|
-
@splits_repository.remove_split(split
|
83
|
+
@splits_repository.remove_split(split)
|
86
84
|
end
|
87
85
|
|
88
86
|
def store_split(split)
|
89
|
-
|
87
|
+
@config.logger.debug("storing split (#{split[:name]})") if @config.debug_enabled
|
90
88
|
|
91
89
|
@splits_repository.add_split(split)
|
92
90
|
end
|
@@ -94,7 +92,7 @@ module SplitIoClient
|
|
94
92
|
private
|
95
93
|
|
96
94
|
def splits_api
|
97
|
-
@splits_api ||= SplitIoClient::Api::Splits.new(@api_key, @metrics)
|
95
|
+
@splits_api ||= SplitIoClient::Api::Splits.new(@api_key, @metrics, @config)
|
98
96
|
end
|
99
97
|
end
|
100
98
|
end
|
@@ -13,10 +13,11 @@ module SplitIoClient
|
|
13
13
|
# @param splits_file [File] file that contains some splits
|
14
14
|
#
|
15
15
|
# @return [LocalhostSplitIoClient] split.io localhost client instance
|
16
|
-
def initialize(splits_file, reload_rate = nil)
|
16
|
+
def initialize(splits_file, config, reload_rate = nil)
|
17
17
|
@localhost_mode = true
|
18
18
|
@localhost_mode_features = []
|
19
19
|
load_localhost_mode_features(splits_file, reload_rate)
|
20
|
+
@config = config
|
20
21
|
end
|
21
22
|
|
22
23
|
#
|
@@ -101,12 +102,12 @@ module SplitIoClient
|
|
101
102
|
parsed_control_treatment = parsed_treatment(control_treatment)
|
102
103
|
|
103
104
|
bucketing_key, matching_key = keys_from_key(key)
|
104
|
-
return parsed_control_treatment unless
|
105
|
+
return parsed_control_treatment unless @config.split_validator.valid_get_treatment_parameters(calling_method, key, split_name, matching_key, bucketing_key, attributes)
|
105
106
|
|
106
107
|
sanitized_split_name = split_name.to_s.strip
|
107
108
|
|
108
109
|
if split_name.to_s != sanitized_split_name
|
109
|
-
|
110
|
+
@config.logger.warn("get_treatment: split_name #{split_name} has extra whitespace, trimming")
|
110
111
|
split_name = sanitized_split_name
|
111
112
|
end
|
112
113
|
|
@@ -127,12 +128,12 @@ module SplitIoClient
|
|
127
128
|
end
|
128
129
|
|
129
130
|
def get_localhost_treatments(key, split_names, attributes = nil, calling_method = 'get_treatments')
|
130
|
-
return nil unless
|
131
|
+
return nil unless @config.split_validator.valid_get_treatments_parameters(calling_method, split_names)
|
131
132
|
|
132
133
|
sanitized_split_names = sanitize_split_names(calling_method, split_names)
|
133
134
|
|
134
135
|
if sanitized_split_names.empty?
|
135
|
-
|
136
|
+
@config.logger.error("#{calling_method}: split_names must be a non-empty Array")
|
136
137
|
return {}
|
137
138
|
end
|
138
139
|
|
@@ -146,10 +147,10 @@ module SplitIoClient
|
|
146
147
|
if (split_name.is_a?(String) || split_name.is_a?(Symbol)) && !split_name.empty?
|
147
148
|
true
|
148
149
|
elsif split_name.is_a?(String) && split_name.empty?
|
149
|
-
|
150
|
+
@config.logger.warn("#{calling_method}: you passed an empty split_name, split_name must be a non-empty String or a Symbol")
|
150
151
|
false
|
151
152
|
else
|
152
|
-
|
153
|
+
@config.logger.warn("#{calling_method}: you passed an invalid split_name, split_name must be a non-empty String or a Symbol")
|
153
154
|
false
|
154
155
|
end
|
155
156
|
end
|
@@ -9,14 +9,16 @@ module SplitIoClient
|
|
9
9
|
# @param api_key [String] the API key for your split account
|
10
10
|
#
|
11
11
|
# @return [SplitIoClient] split.io client instance
|
12
|
-
def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository)
|
12
|
+
def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config)
|
13
|
+
@api_key = api_key
|
13
14
|
@splits_repository = splits_repository
|
14
15
|
@segments_repository = segments_repository
|
15
16
|
@impressions_repository = impressions_repository
|
16
17
|
@metrics_repository = metrics_repository
|
17
18
|
@events_repository = events_repository
|
19
|
+
@sdk_blocker = sdk_blocker
|
18
20
|
@destroyed = false
|
19
|
-
|
21
|
+
@config = config
|
20
22
|
@adapter = adapter
|
21
23
|
end
|
22
24
|
|
@@ -52,27 +54,30 @@ module SplitIoClient
|
|
52
54
|
end
|
53
55
|
|
54
56
|
def destroy
|
55
|
-
|
57
|
+
@config.logger.info('Split client shutdown started...') if @config.debug_enabled
|
56
58
|
|
57
|
-
|
59
|
+
@config.threads.select { |name, thread| name.to_s.end_with? 'sender' }.values.each do |thread|
|
58
60
|
thread.raise(SplitIoClient::SDKShutdownException)
|
59
61
|
thread.join
|
60
62
|
end
|
61
63
|
|
62
|
-
|
64
|
+
@config.threads.values.each { |thread| Thread.kill(thread) }
|
63
65
|
|
64
66
|
@splits_repository.clear
|
65
67
|
@segments_repository.clear
|
66
68
|
|
67
|
-
SplitIoClient.
|
68
|
-
SplitIoClient.
|
69
|
+
SplitIoClient.load_factory_registry
|
70
|
+
SplitIoClient.split_factory_registry.remove(@api_key)
|
71
|
+
|
72
|
+
@config.logger.info('Split client shutdown complete') if @config.debug_enabled
|
73
|
+
@config.valid_mode = false
|
69
74
|
@destroyed = true
|
70
75
|
end
|
71
76
|
|
72
77
|
def store_impression(split_name, matching_key, bucketing_key, treatment, store_impressions, attributes)
|
73
78
|
time = (Time.now.to_f * 1000.0).to_i
|
74
79
|
|
75
|
-
return if
|
80
|
+
return if @config.disable_impressions || !store_impressions
|
76
81
|
|
77
82
|
@impressions_repository.add(
|
78
83
|
matching_key,
|
@@ -85,7 +90,7 @@ module SplitIoClient
|
|
85
90
|
route_impression(split_name, matching_key, bucketing_key, time, treatment, attributes)
|
86
91
|
|
87
92
|
rescue StandardError => error
|
88
|
-
|
93
|
+
@config.log_found_exception(__method__.to_s, error)
|
89
94
|
end
|
90
95
|
|
91
96
|
def route_impression(split_name, matching_key, bucketing_key, time, treatment, attributes)
|
@@ -111,11 +116,11 @@ module SplitIoClient
|
|
111
116
|
end
|
112
117
|
|
113
118
|
def impression_router
|
114
|
-
@impression_router ||= SplitIoClient::ImpressionRouter.new
|
119
|
+
@impression_router ||= SplitIoClient::ImpressionRouter.new(@config)
|
115
120
|
end
|
116
121
|
|
117
122
|
def track(key, traffic_type_name, event_type, value = nil, properties = nil)
|
118
|
-
return false unless valid_client &&
|
123
|
+
return false unless valid_client && @config.split_validator.valid_track_parameters(key, traffic_type_name, event_type, value, properties)
|
119
124
|
|
120
125
|
properties_size = EVENT_AVERAGE_SIZE
|
121
126
|
|
@@ -123,16 +128,22 @@ module SplitIoClient
|
|
123
128
|
properties, size = validate_properties(properties)
|
124
129
|
properties_size += size
|
125
130
|
if (properties_size > EVENTS_SIZE_THRESHOLD)
|
126
|
-
|
131
|
+
@config.logger.error("The maximum size allowed for the properties is #{EVENTS_SIZE_THRESHOLD}. Current is #{properties_size}. Event not queued")
|
127
132
|
return false
|
128
133
|
end
|
129
134
|
end
|
130
135
|
|
136
|
+
if ready? && !@splits_repository.traffic_type_exists(traffic_type_name)
|
137
|
+
@config.logger.warn("track: Traffic Type #{traffic_type_name} " \
|
138
|
+
"does not have any corresponding Splits in this environment, make sure you're tracking " \
|
139
|
+
'your events to a valid traffic type defined in the Split console')
|
140
|
+
end
|
141
|
+
|
131
142
|
begin
|
132
143
|
@events_repository.add(key.to_s, traffic_type_name.downcase, event_type.to_s, (Time.now.to_f * 1000).to_i, value, properties, properties_size)
|
133
144
|
true
|
134
145
|
rescue StandardError => error
|
135
|
-
|
146
|
+
@config.log_found_exception(__method__.to_s, error)
|
136
147
|
false
|
137
148
|
end
|
138
149
|
end
|
@@ -167,15 +178,19 @@ module SplitIoClient
|
|
167
178
|
if (split_name.is_a?(String) || split_name.is_a?(Symbol)) && !split_name.empty?
|
168
179
|
true
|
169
180
|
elsif split_name.is_a?(String) && split_name.empty?
|
170
|
-
|
181
|
+
@config.logger.warn("#{calling_method}: you passed an empty split_name, split_name must be a non-empty String or a Symbol")
|
171
182
|
false
|
172
183
|
else
|
173
|
-
|
184
|
+
@config.logger.warn("#{calling_method}: you passed an invalid split_name, split_name must be a non-empty String or a Symbol")
|
174
185
|
false
|
175
186
|
end
|
176
187
|
end
|
177
188
|
end
|
178
189
|
|
190
|
+
def block_until_ready(time = nil)
|
191
|
+
@sdk_blocker.block(time) if @sdk_blocker && !@sdk_blocker.ready?
|
192
|
+
end
|
193
|
+
|
179
194
|
private
|
180
195
|
|
181
196
|
def validate_properties(properties)
|
@@ -191,32 +206,32 @@ module SplitIoClient
|
|
191
206
|
result[key] = value
|
192
207
|
size += variable_size(value)
|
193
208
|
else
|
194
|
-
|
209
|
+
@config.logger.warn("Property #{key} is of invalid type. Setting value to nil")
|
195
210
|
result[key] = nil
|
196
211
|
end
|
197
212
|
end
|
198
213
|
}
|
199
214
|
|
200
|
-
|
215
|
+
@config.logger.warn('Event has more than 300 properties. Some of them will be trimmed when processed') if properties_count > 300
|
201
216
|
|
202
217
|
return fixed_properties, size
|
203
218
|
end
|
204
219
|
|
205
220
|
def valid_client
|
206
221
|
if @destroyed
|
207
|
-
|
222
|
+
@config.logger.error('Client has already been destroyed - no calls possible')
|
208
223
|
return false
|
209
224
|
end
|
210
|
-
|
225
|
+
@config.valid_mode
|
211
226
|
end
|
212
227
|
|
213
228
|
def treatments(key, split_names, attributes = {}, calling_method = 'get_treatments')
|
214
|
-
return nil unless
|
229
|
+
return nil unless @config.split_validator.valid_get_treatments_parameters(calling_method, split_names)
|
215
230
|
|
216
231
|
sanitized_split_names = sanitize_split_names(calling_method, split_names)
|
217
232
|
|
218
233
|
if sanitized_split_names.empty?
|
219
|
-
|
234
|
+
@config.logger.error("#{calling_method}: split_names must be a non-empty Array")
|
220
235
|
return {}
|
221
236
|
end
|
222
237
|
|
@@ -224,7 +239,7 @@ module SplitIoClient
|
|
224
239
|
bucketing_key = bucketing_key ? bucketing_key.to_s : nil
|
225
240
|
matching_key = matching_key ? matching_key.to_s : nil
|
226
241
|
|
227
|
-
evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, true)
|
242
|
+
evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @config, true)
|
228
243
|
start = Time.now
|
229
244
|
treatments_labels_change_numbers =
|
230
245
|
@splits_repository.get_splits(sanitized_split_names).each_with_object({}) do |(name, data), memo|
|
@@ -234,7 +249,7 @@ module SplitIoClient
|
|
234
249
|
# Measure
|
235
250
|
@adapter.metrics.time('sdk.' + calling_method, latency)
|
236
251
|
|
237
|
-
unless
|
252
|
+
unless @config.disable_impressions
|
238
253
|
time = (Time.now.to_f * 1000.0).to_i
|
239
254
|
@impressions_repository.add_bulk(
|
240
255
|
matching_key, bucketing_key, treatments_labels_change_numbers, time
|
@@ -269,38 +284,48 @@ module SplitIoClient
|
|
269
284
|
key, split_name, attributes = {}, split_data = nil, store_impressions = true,
|
270
285
|
multiple = false, evaluator = nil, calling_method = 'get_treatment'
|
271
286
|
)
|
272
|
-
control_treatment = {
|
273
|
-
|
287
|
+
control_treatment = { treatment: Engine::Models::Treatment::CONTROL }
|
288
|
+
|
289
|
+
parsed_control_exception = parsed_treatment(multiple,
|
290
|
+
control_treatment.merge({ label: Engine::Models::Label::EXCEPTION }))
|
274
291
|
|
275
292
|
bucketing_key, matching_key = keys_from_key(key)
|
276
293
|
|
277
|
-
return
|
294
|
+
return parsed_control_exception unless valid_client && @config.split_validator.valid_get_treatment_parameters(calling_method, key, split_name, matching_key, bucketing_key, attributes)
|
278
295
|
|
279
296
|
bucketing_key = bucketing_key ? bucketing_key.to_s : nil
|
280
297
|
matching_key = matching_key.to_s
|
281
298
|
sanitized_split_name = split_name.to_s.strip
|
282
299
|
|
283
300
|
if split_name.to_s != sanitized_split_name
|
284
|
-
|
301
|
+
@config.logger.warn("#{calling_method}: split_name #{split_name} has extra whitespace, trimming")
|
285
302
|
split_name = sanitized_split_name
|
286
303
|
end
|
287
304
|
|
288
|
-
evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
|
305
|
+
evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @config)
|
289
306
|
|
290
307
|
begin
|
291
308
|
start = Time.now
|
292
309
|
|
293
310
|
split = multiple ? split_data : @splits_repository.get_split(split_name)
|
294
311
|
|
295
|
-
if split.nil?
|
296
|
-
|
297
|
-
|
312
|
+
if split.nil? && ready?
|
313
|
+
@config.logger.warn("#{calling_method}: you passed #{split_name} that " \
|
314
|
+
'does not exist in this environment, please double check what Splits exist in the web console')
|
315
|
+
|
316
|
+
return parsed_treatment(multiple, control_treatment.merge({ label: Engine::Models::Label::NOT_FOUND }))
|
298
317
|
end
|
299
318
|
|
300
319
|
treatment_data =
|
320
|
+
if !split.nil? && ready?
|
301
321
|
evaluator.call(
|
302
|
-
|
303
|
-
|
322
|
+
{ bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
|
323
|
+
)
|
324
|
+
else
|
325
|
+
@config.logger.error("#{calling_method}: the SDK is not ready, the operation cannot be executed")
|
326
|
+
|
327
|
+
control_treatment.merge({ label: Engine::Models::Label::NOT_READY })
|
328
|
+
end
|
304
329
|
|
305
330
|
latency = (Time.now - start) * 1000.0
|
306
331
|
store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
|
@@ -308,11 +333,11 @@ module SplitIoClient
|
|
308
333
|
# Measure
|
309
334
|
@adapter.metrics.time('sdk.' + calling_method, latency) unless multiple
|
310
335
|
rescue StandardError => error
|
311
|
-
|
336
|
+
@config.log_found_exception(__method__.to_s, error)
|
312
337
|
|
313
338
|
store_impression(split_name, matching_key, bucketing_key, control_treatment, store_impressions, attributes)
|
314
339
|
|
315
|
-
return
|
340
|
+
return parsed_control_exception
|
316
341
|
end
|
317
342
|
|
318
343
|
parsed_treatment(multiple, treatment_data)
|
@@ -321,5 +346,10 @@ module SplitIoClient
|
|
321
346
|
def variable_size(value)
|
322
347
|
value.is_a?(String) ? value.length : 0
|
323
348
|
end
|
349
|
+
|
350
|
+
def ready?
|
351
|
+
return @sdk_blocker.ready? if @sdk_blocker
|
352
|
+
true
|
353
|
+
end
|
324
354
|
end
|
325
355
|
end
|
@@ -7,17 +7,21 @@ module SplitIoClient
|
|
7
7
|
class Client
|
8
8
|
RUBY_ENCODING = '1.9'.respond_to?(:force_encoding)
|
9
9
|
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
10
14
|
def get_api(url, api_key, params = {})
|
11
15
|
api_client.get(url, params) do |req|
|
12
16
|
req.headers = common_headers(api_key).merge('Accept-Encoding' => 'gzip')
|
13
17
|
|
14
|
-
req.options[:timeout] =
|
15
|
-
req.options[:open_timeout] =
|
18
|
+
req.options[:timeout] = @config.read_timeout
|
19
|
+
req.options[:open_timeout] = @config.connection_timeout
|
16
20
|
|
17
|
-
|
21
|
+
@config.split_logger.log_if_debug("GET #{url} proxy: #{api_client.proxy}")
|
18
22
|
end
|
19
23
|
rescue StandardError => e
|
20
|
-
|
24
|
+
@config.logger.warn("#{e}\nURL:#{url}\nparams:#{params}")
|
21
25
|
raise e, 'Split SDK failed to connect to backend to retrieve information', e.backtrace
|
22
26
|
end
|
23
27
|
|
@@ -29,14 +33,14 @@ module SplitIoClient
|
|
29
33
|
|
30
34
|
req.body = data.to_json
|
31
35
|
|
32
|
-
req.options[:timeout] =
|
33
|
-
req.options[:open_timeout] =
|
36
|
+
req.options[:timeout] = @config.read_timeout
|
37
|
+
req.options[:open_timeout] = @config.connection_timeout
|
34
38
|
|
35
|
-
|
36
|
-
|
39
|
+
@config.split_logger.log_if_transport("POST #{url} #{req.body}")
|
40
|
+
@config.split_logger.log_if_debug("POST #{url}")
|
37
41
|
end
|
38
42
|
rescue StandardError => e
|
39
|
-
|
43
|
+
@config.logger.warn("#{e}\nURL:#{url}\ndata:#{data}\nparams:#{params}")
|
40
44
|
raise e, 'Split SDK failed to connect to backend to post information', e.backtrace
|
41
45
|
end
|
42
46
|
|
@@ -73,15 +77,15 @@ module SplitIoClient
|
|
73
77
|
def common_headers(api_key)
|
74
78
|
{
|
75
79
|
'Authorization' => "Bearer #{api_key}",
|
76
|
-
'SplitSDKVersion' => "#{
|
77
|
-
'SplitSDKMachineName' =>
|
78
|
-
'SplitSDKMachineIP' =>
|
80
|
+
'SplitSDKVersion' => "#{@config.language}-#{@config.version}",
|
81
|
+
'SplitSDKMachineName' => @config.machine_name,
|
82
|
+
'SplitSDKMachineIP' => @config.machine_ip,
|
79
83
|
'Referer' => referer
|
80
84
|
}
|
81
85
|
end
|
82
86
|
|
83
87
|
def referer
|
84
|
-
result = "#{
|
88
|
+
result = "#{@config.language}-#{@config.version}"
|
85
89
|
|
86
90
|
result = "#{result}::#{SplitIoClient::SplitConfig.machine_hostname}" unless SplitIoClient::SplitConfig.machine_hostname == 'localhost'
|
87
91
|
|