splitclient-rb 8.4.0.rc.1-java → 8.5.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGES.txt +8 -0
- data/LICENSE +1 -1
- data/lib/splitclient-rb/cache/filter/bloom_filter.rb +10 -6
- data/lib/splitclient-rb/clients/split_client.rb +18 -20
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +24 -27
- data/lib/splitclient-rb/engine/synchronizer.rb +4 -4
- data/lib/splitclient-rb/helpers/repository_helper.rb +7 -0
- data/lib/splitclient-rb/managers/split_manager.rb +2 -1
- data/lib/splitclient-rb/split_factory.rb +2 -13
- data/lib/splitclient-rb/version.rb +1 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 835ab35a58b3ae0aa8ea577dc648f441695c241574e5cb3d9860bfeae8eca0f2
|
4
|
+
data.tar.gz: f6000cd2a2e3764691c73efee56b22c7f0baa9a9b86c955e40a489fae18f151a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af8be0126a7f070f2a3cdaa99fb18d34c0fadbaac51a206ed77a4edfb468c913fc50c8d47ad6ee671fee2623507307101c0eaf18dff441d2266435cc906b57fc
|
7
|
+
data.tar.gz: 26d1d6dfbef54c5407ad71a8413e342ae62f6844bc099c402662658cd1870dd761a4b7a407feca8370e91187f4cedc868826828e86467cfe069ff0dabd341030
|
data/CHANGES.txt
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
CHANGES
|
2
2
|
|
3
|
+
8.5.0 (Jan 17, 2025)
|
4
|
+
- Fixed high cpu usage when unique keys are cleared every 24 hours.
|
5
|
+
- Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on SplitView type objects. Read more in our docs.
|
6
|
+
|
7
|
+
8.4.0 (May 3, 2024)
|
8
|
+
- Fixed issue preventing Impressopns and Events posting if client.destroy is called before the post threads started
|
9
|
+
- Added support for targeting rules based on semantic versions (https://semver.org/).
|
10
|
+
|
3
11
|
8.3.1 (Mar 22, 2024)
|
4
12
|
- Fixed ruby process hanging due to failed thread.join command, when calling destroy and a http request still active.
|
5
13
|
- Fixed streaming notification parser. Issue ref: https://github.com/splitio/ruby-client/issues/511
|
data/LICENSE
CHANGED
@@ -8,8 +8,8 @@ module SplitIoClient
|
|
8
8
|
class BloomFilter
|
9
9
|
def initialize(capacity, false_positive_probability = 0.001)
|
10
10
|
@capacity = capacity.round
|
11
|
-
m = best_m(capacity, false_positive_probability)
|
12
|
-
|
11
|
+
@m = best_m(capacity, false_positive_probability)
|
12
|
+
reset_filter
|
13
13
|
@k = best_k(capacity)
|
14
14
|
end
|
15
15
|
|
@@ -17,22 +17,26 @@ module SplitIoClient
|
|
17
17
|
return false if contains?(string)
|
18
18
|
|
19
19
|
positions = hashes(string)
|
20
|
-
|
21
20
|
positions.each { |position| @ba[position] = 1 }
|
22
21
|
|
23
22
|
true
|
24
23
|
end
|
25
|
-
|
24
|
+
|
26
25
|
def contains?(string)
|
27
26
|
!hashes(string).any? { |ea| @ba[ea] == 0 }
|
28
27
|
end
|
29
28
|
|
30
29
|
def clear
|
31
|
-
@ba
|
30
|
+
@ba = nil
|
31
|
+
reset_filter
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
private
|
35
35
|
|
36
|
+
def reset_filter
|
37
|
+
@ba = BitArray.new(@m.round)
|
38
|
+
end
|
39
|
+
|
36
40
|
# m is the required number of bits in the array
|
37
41
|
def best_m(capacity, false_positive_probability)
|
38
42
|
-(capacity * Math.log(false_positive_probability)) / (Math.log(2) ** 2)
|
@@ -267,7 +267,7 @@ module SplitIoClient
|
|
267
267
|
to_return = Hash.new
|
268
268
|
sanitized_feature_flag_names.each {|name|
|
269
269
|
to_return[name.to_sym] = control_treatment_with_config
|
270
|
-
impressions << @impressions_manager.build_impression(matching_key, bucketing_key, name.to_sym, control_treatment_with_config.merge({ label
|
270
|
+
impressions << { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, name.to_sym, control_treatment_with_config.merge({ :label => Engine::Models::Label::NOT_READY }), false, { attributes: attributes, time: nil }), :disabled => false }
|
271
271
|
}
|
272
272
|
@impressions_manager.track(impressions)
|
273
273
|
return to_return
|
@@ -278,7 +278,6 @@ module SplitIoClient
|
|
278
278
|
valid_feature_flag_names << feature_flag_name unless feature_flag_name.nil?
|
279
279
|
}
|
280
280
|
start = Time.now
|
281
|
-
impressions_total = []
|
282
281
|
|
283
282
|
feature_flags = @splits_repository.splits(valid_feature_flag_names)
|
284
283
|
treatments = Hash.new
|
@@ -291,15 +290,14 @@ module SplitIoClient
|
|
291
290
|
next
|
292
291
|
end
|
293
292
|
treatments_labels_change_numbers, impressions = evaluate_treatment(feature_flag, key, bucketing_key, matching_key, attributes, calling_method)
|
294
|
-
impressions_total.concat(impressions) unless impressions.nil?
|
295
293
|
treatments[key] =
|
296
294
|
{
|
297
295
|
treatment: treatments_labels_change_numbers[:treatment],
|
298
296
|
config: treatments_labels_change_numbers[:config]
|
299
297
|
}
|
298
|
+
@impressions_manager.track(impressions) unless impressions.empty?
|
300
299
|
end
|
301
300
|
record_latency(calling_method, start)
|
302
|
-
@impressions_manager.track(impressions_total) unless impressions_total.empty?
|
303
301
|
|
304
302
|
treatments.merge(invalid_treatments)
|
305
303
|
end
|
@@ -332,50 +330,50 @@ module SplitIoClient
|
|
332
330
|
end
|
333
331
|
|
334
332
|
feature_flag = @splits_repository.get_split(feature_flag_name)
|
335
|
-
treatments,
|
333
|
+
treatments, impressions_decorator = evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple)
|
336
334
|
|
337
|
-
@impressions_manager.track(
|
335
|
+
@impressions_manager.track(impressions_decorator) unless impressions_decorator.nil?
|
338
336
|
treatments
|
339
337
|
end
|
340
338
|
|
341
339
|
def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple = false)
|
342
|
-
|
340
|
+
impressions_decorator = []
|
343
341
|
begin
|
344
342
|
start = Time.now
|
345
343
|
if feature_flag.nil? && ready?
|
346
344
|
@config.logger.warn("#{calling_method}: you passed #{feature_flag_name} that " \
|
347
345
|
'does not exist in this environment, please double check what feature flags exist in the Split user interface')
|
348
|
-
return parsed_treatment(control_treatment.merge({ label
|
346
|
+
return parsed_treatment(control_treatment.merge({ :label => Engine::Models::Label::NOT_FOUND }), multiple), nil
|
349
347
|
end
|
350
|
-
|
348
|
+
|
351
349
|
if !feature_flag.nil? && ready?
|
352
|
-
@evaluator.evaluate_feature_flag(
|
350
|
+
treatment_data = @evaluator.evaluate_feature_flag(
|
353
351
|
{ bucketing_key: bucketing_key, matching_key: matching_key }, feature_flag, attributes
|
354
352
|
)
|
353
|
+
impressions_disabled = feature_flag[:impressionsDisabled]
|
355
354
|
else
|
356
355
|
@config.logger.error("#{calling_method}: the SDK is not ready, results may be incorrect for feature flag #{feature_flag_name}. Make sure to wait for SDK readiness before using this method.")
|
357
|
-
control_treatment.merge({ label
|
356
|
+
treatment_data = control_treatment.merge({ :label => Engine::Models::Label::NOT_READY })
|
357
|
+
impressions_disabled = false
|
358
358
|
end
|
359
359
|
|
360
360
|
record_latency(calling_method, start)
|
361
|
-
|
362
|
-
|
361
|
+
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, treatment_data, impressions_disabled, { attributes: attributes, time: nil }), :disabled => impressions_disabled }
|
362
|
+
impressions_decorator << impression_decorator unless impression_decorator.nil?
|
363
363
|
rescue StandardError => e
|
364
364
|
@config.log_found_exception(__method__.to_s, e)
|
365
|
-
|
366
365
|
record_exception(calling_method)
|
366
|
+
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, control_treatment, false, { attributes: attributes, time: nil }), :disabled => false }
|
367
|
+
impressions_decorator << impression_decorator unless impression_decorator.nil?
|
367
368
|
|
368
|
-
|
369
|
-
impressions << impression unless impression.nil?
|
370
|
-
|
371
|
-
return parsed_treatment(control_treatment.merge({ label: Engine::Models::Label::EXCEPTION }), multiple), impressions
|
369
|
+
return parsed_treatment(control_treatment.merge({ :label => Engine::Models::Label::EXCEPTION }), multiple), impressions_decorator
|
372
370
|
end
|
373
371
|
|
374
|
-
return parsed_treatment(treatment_data, multiple),
|
372
|
+
return parsed_treatment(treatment_data, multiple), impressions_decorator
|
375
373
|
end
|
376
374
|
|
377
375
|
def control_treatment
|
378
|
-
{ treatment
|
376
|
+
{ :treatment => Engine::Models::Treatment::CONTROL }
|
379
377
|
end
|
380
378
|
|
381
379
|
def control_treatment_with_config
|
@@ -18,19 +18,16 @@ module SplitIoClient
|
|
18
18
|
@unique_keys_tracker = unique_keys_tracker
|
19
19
|
end
|
20
20
|
|
21
|
-
def build_impression(matching_key, bucketing_key, split_name,
|
22
|
-
impression_data = impression_data(matching_key, bucketing_key, split_name,
|
23
|
-
|
21
|
+
def build_impression(matching_key, bucketing_key, split_name, treatment_data, impressions_disabled, params = {})
|
22
|
+
impression_data = impression_data(matching_key, bucketing_key, split_name, treatment_data, params[:time])
|
24
23
|
begin
|
25
|
-
|
26
|
-
when :debug # In DEBUG mode we should calculate the pt only.
|
27
|
-
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
|
28
|
-
when :none # In NONE mode we should track the total amount of evaluations and the unique keys.
|
24
|
+
if @config.impressions_mode == :none || impressions_disabled
|
29
25
|
@impression_counter.inc(split_name, impression_data[:m])
|
30
26
|
@unique_keys_tracker.track(split_name, matching_key)
|
27
|
+
elsif @config.impressions_mode == :debug # In DEBUG mode we should calculate the pt only.
|
28
|
+
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
|
31
29
|
else # In OPTIMIZED mode we should track the total amount of evaluations and deduplicate the impressions.
|
32
30
|
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
|
33
|
-
|
34
31
|
@impression_counter.inc(split_name, impression_data[:m]) unless impression_data[:pt].nil?
|
35
32
|
end
|
36
33
|
rescue StandardError => e
|
@@ -40,24 +37,25 @@ module SplitIoClient
|
|
40
37
|
impression(impression_data, params[:attributes])
|
41
38
|
end
|
42
39
|
|
43
|
-
def track(
|
44
|
-
return if
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
40
|
+
def track(impressions_decorator)
|
41
|
+
return if impressions_decorator.empty?
|
42
|
+
|
43
|
+
impressions_decorator.each do |impression_decorator|
|
44
|
+
impression_router.add_bulk([impression_decorator[:impression]])
|
45
|
+
stats = { dropped: 0, queued: 0, dedupe: 0 }
|
46
|
+
begin
|
47
|
+
next if @config.impressions_mode == :none || impression_decorator[:disabled]
|
48
|
+
|
49
|
+
if @config.impressions_mode == :debug
|
50
|
+
track_debug_mode([impression_decorator[:impression]], stats)
|
51
|
+
else
|
52
|
+
track_optimized_mode([impression_decorator[:impression]], stats)
|
53
|
+
end
|
54
|
+
rescue StandardError => e
|
55
|
+
@config.log_found_exception(__method__.to_s, e)
|
56
|
+
ensure
|
57
|
+
record_stats(stats)
|
55
58
|
end
|
56
|
-
rescue StandardError => e
|
57
|
-
@config.log_found_exception(__method__.to_s, e)
|
58
|
-
ensure
|
59
|
-
record_stats(stats)
|
60
|
-
impression_router.add_bulk(impressions)
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
@@ -126,11 +124,10 @@ module SplitIoClient
|
|
126
124
|
|
127
125
|
def track_optimized_mode(impressions, stats)
|
128
126
|
optimized_impressions = impressions.select { |imp| should_queue_impression?(imp[:i]) }
|
129
|
-
|
127
|
+
stats[:dedupe] = impressions.length - optimized_impressions.length
|
130
128
|
return if optimized_impressions.empty?
|
131
129
|
|
132
130
|
stats[:dropped] = @impressions_repository.add_bulk(optimized_impressions)
|
133
|
-
stats[:dedupe] = impressions.length - optimized_impressions.length
|
134
131
|
stats[:queued] = optimized_impressions.length - stats[:dropped]
|
135
132
|
end
|
136
133
|
end
|
@@ -48,7 +48,7 @@ module SplitIoClient
|
|
48
48
|
events_sender
|
49
49
|
start_telemetry_sync_task
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
impressions_count_sender
|
53
53
|
start_unique_keys_tracker_task
|
54
54
|
end
|
@@ -175,7 +175,7 @@ module SplitIoClient
|
|
175
175
|
|
176
176
|
# Starts thread which loops constantly and sends impressions to the Split API
|
177
177
|
def impressions_sender
|
178
|
-
ImpressionsSender.new(@impressions_repository, @config, @impressions_api).call
|
178
|
+
ImpressionsSender.new(@impressions_repository, @config, @impressions_api).call
|
179
179
|
end
|
180
180
|
|
181
181
|
# Starts thread which loops constantly and sends events to the Split API
|
@@ -185,7 +185,7 @@ module SplitIoClient
|
|
185
185
|
|
186
186
|
# Starts thread which loops constantly and sends impressions count to the Split API
|
187
187
|
def impressions_count_sender
|
188
|
-
ImpressionsCountSender.new(@config, @impression_counter, @impressions_sender_adapter).call
|
188
|
+
ImpressionsCountSender.new(@config, @impression_counter, @impressions_sender_adapter).call
|
189
189
|
end
|
190
190
|
|
191
191
|
def start_telemetry_sync_task
|
@@ -203,7 +203,7 @@ module SplitIoClient
|
|
203
203
|
def sync_splits_and_segments
|
204
204
|
@config.logger.debug('Synchronizing feature flags and segments ...') if @config.debug_enabled
|
205
205
|
splits_result = @split_fetcher.fetch_splits
|
206
|
-
|
206
|
+
|
207
207
|
splits_result[:success] && @segment_fetcher.fetch_segments
|
208
208
|
end
|
209
209
|
end
|
@@ -13,6 +13,13 @@ module SplitIoClient
|
|
13
13
|
next
|
14
14
|
end
|
15
15
|
|
16
|
+
unless feature_flag.key?(:impressionsDisabled)
|
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
|
22
|
+
|
16
23
|
config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled
|
17
24
|
to_add.push(feature_flag)
|
18
25
|
end
|
@@ -107,7 +107,8 @@ module SplitIoClient
|
|
107
107
|
change_number: split[:changeNumber],
|
108
108
|
configs: split[:configurations] || {},
|
109
109
|
sets: split[:sets] || [],
|
110
|
-
default_treatment: split[:defaultTreatment]
|
110
|
+
default_treatment: split[:defaultTreatment],
|
111
|
+
impressions_disabled: split[:impressionsDisabled]
|
111
112
|
}
|
112
113
|
end
|
113
114
|
|
@@ -230,11 +230,6 @@ module SplitIoClient
|
|
230
230
|
end
|
231
231
|
|
232
232
|
def build_unique_keys_tracker
|
233
|
-
if @config.impressions_mode != :none
|
234
|
-
@unique_keys_tracker = Engine::Impressions::NoopUniqueKeysTracker.new
|
235
|
-
return
|
236
|
-
end
|
237
|
-
|
238
233
|
bf = Cache::Filter::BloomFilter.new(30_000_000)
|
239
234
|
filter_adapter = Cache::Filter::FilterAdapter.new(@config, bf)
|
240
235
|
cache = Concurrent::Hash.new
|
@@ -242,8 +237,7 @@ module SplitIoClient
|
|
242
237
|
end
|
243
238
|
|
244
239
|
def build_impressions_observer
|
245
|
-
if (@config.cache_adapter == :redis && @config.impressions_mode != :optimized)
|
246
|
-
(@config.cache_adapter == :memory && @config.impressions_mode == :none)
|
240
|
+
if (@config.cache_adapter == :redis && @config.impressions_mode != :optimized)
|
247
241
|
@impression_observer = Observers::NoopImpressionObserver.new
|
248
242
|
else
|
249
243
|
@impression_observer = Observers::ImpressionObserver.new
|
@@ -251,12 +245,7 @@ module SplitIoClient
|
|
251
245
|
end
|
252
246
|
|
253
247
|
def build_impression_counter
|
254
|
-
|
255
|
-
when :debug
|
256
|
-
@impression_counter = Engine::Common::NoopImpressionCounter.new
|
257
|
-
else
|
258
|
-
@impression_counter = Engine::Common::ImpressionCounter.new
|
259
|
-
end
|
248
|
+
@impression_counter = Engine::Common::ImpressionCounter.new
|
260
249
|
end
|
261
250
|
|
262
251
|
def build_impressions_sender_adapter
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: splitclient-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.5.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Split Software
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -585,12 +585,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
585
585
|
version: 2.5.0
|
586
586
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
587
587
|
requirements:
|
588
|
-
- - "
|
588
|
+
- - ">="
|
589
589
|
- !ruby/object:Gem::Version
|
590
|
-
version:
|
590
|
+
version: '0'
|
591
591
|
requirements: []
|
592
|
-
|
593
|
-
rubygems_version: 2.6.14
|
592
|
+
rubygems_version: 3.2.33
|
594
593
|
signing_key:
|
595
594
|
specification_version: 4
|
596
595
|
summary: Ruby client for split SDK.
|