splitclient-rb 8.4.0.rc.1-java → 8.5.0.pre.rc1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 73e079065e870c6f14c7a92d91e7e2fe5a5c3be2
4
- data.tar.gz: 563e6a64dac818c1a62d87a8b66e52dcd717245f
2
+ SHA256:
3
+ metadata.gz: ae5f1fbbb687903fd0a98042e18c1ff9468fbe97f4f5f38d7f4a77799d6aa45a
4
+ data.tar.gz: '0329c956f96db007b266007b5e68b3b89933f134f3f40564127602147ef48da1'
5
5
  SHA512:
6
- metadata.gz: ec39fc898c10c97863187492007e4a9b1cd4c56144dcc2b7b49255ad8583b0df601c2b3af7cdfa9e3c4e965fa29205d88eeee80d25ae2a9742e181b1050e71f8
7
- data.tar.gz: 79764d433ed88a95ba08e7f6f32dcc8009a27e8765728291dca7245548ff0d92a44cfce3b875835e3c1670a90f5b10a74a03a18967273a2aa735690dd9f1af09
6
+ metadata.gz: 57e12b770da34ec5d84ce8e6860fa92eee0d231e43909525a7777986edfdd3d933fd2f87265254876c0e4c81ee3815c598675ffb76ced1b637e9817638cf2ce0
7
+ data.tar.gz: 60043e9df123dd083d0d0523fd8ca99e7bf0acb4d4d44e694fa2422a4c2d81767b9551209ad4bf905826380824b0fce71543dae2b52743f77a1c44a4ad9328bf
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
@@ -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
- @ba = BitArray.new(m.round)
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.size.times { |i| @ba[i] = 0 }
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: Engine::Models::Label::NOT_READY }), { attributes: attributes, time: nil })
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, impressions = evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple)
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(impressions) unless impressions.nil?
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
- impressions = []
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: Engine::Models::Label::NOT_FOUND }), multiple), nil
346
+ return parsed_treatment(control_treatment.merge({ :label => Engine::Models::Label::NOT_FOUND }), multiple), nil
349
347
  end
350
- treatment_data =
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: Engine::Models::Label::NOT_READY })
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
- impression = @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, treatment_data, { attributes: attributes, time: nil })
362
- impressions << impression unless impression.nil?
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
- impression = @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, control_treatment, { attributes: attributes, time: nil })
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), impressions
372
+ return parsed_treatment(treatment_data, multiple), impressions_decorator
375
373
  end
376
374
 
377
375
  def control_treatment
378
- { treatment: Engine::Models::Treatment::CONTROL }
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, treatment, params = {})
22
- impression_data = impression_data(matching_key, bucketing_key, split_name, treatment, params[:time])
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
- case @config.impressions_mode
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(impressions)
44
- return if impressions.empty?
45
-
46
- stats = { dropped: 0, queued: 0, dedupe: 0 }
47
- begin
48
- case @config.impressions_mode
49
- when :none
50
- return
51
- when :debug
52
- track_debug_mode(impressions, stats)
53
- when :optimized
54
- track_optimized_mode(impressions, stats)
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 unless @config.impressions_mode == :none
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 unless @config.impressions_mode == :debug
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
- case @config.impressions_mode
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
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '8.4.0.rc.1'
2
+ VERSION = '8.5.0.pre.rc1'
3
3
  end
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.0.rc.1
4
+ version: 8.5.0.pre.rc1
5
5
  platform: java
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-02 00:00:00.000000000 Z
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
@@ -589,8 +589,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
589
589
  - !ruby/object:Gem::Version
590
590
  version: 1.3.1
591
591
  requirements: []
592
- rubyforge_project:
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.