Skip to content

Commit b04348f

Browse files
authored
Merge pull request #539 from splitio/imp-toggle-engine
updated engine classes and repo helper
2 parents 49d9abe + 776413d commit b04348f

19 files changed

+573
-160
lines changed

lib/splitclient-rb/clients/split_client.rb

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ def treatments(key, feature_flag_names, attributes = {}, calling_method = 'get_t
267267
to_return = Hash.new
268268
sanitized_feature_flag_names.each {|name|
269269
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 }
271271
}
272272
@impressions_manager.track(impressions)
273273
return to_return
@@ -278,7 +278,6 @@ def treatments(key, feature_flag_names, attributes = {}, calling_method = 'get_t
278278
valid_feature_flag_names << feature_flag_name unless feature_flag_name.nil?
279279
}
280280
start = Time.now
281-
impressions_total = []
282281

283282
feature_flags = @splits_repository.splits(valid_feature_flag_names)
284283
treatments = Hash.new
@@ -291,15 +290,14 @@ def treatments(key, feature_flag_names, attributes = {}, calling_method = 'get_t
291290
next
292291
end
293292
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?
295293
treatments[key] =
296294
{
297295
treatment: treatments_labels_change_numbers[:treatment],
298296
config: treatments_labels_change_numbers[:config]
299297
}
298+
@impressions_manager.track(impressions) unless impressions.empty?
300299
end
301300
record_latency(calling_method, start)
302-
@impressions_manager.track(impressions_total) unless impressions_total.empty?
303301

304302
treatments.merge(invalid_treatments)
305303
end
@@ -332,50 +330,50 @@ def treatment(key, feature_flag_name, attributes = {}, split_data = nil, store_i
332330
end
333331

334332
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)
336334

337-
@impressions_manager.track(impressions) unless impressions.nil?
335+
@impressions_manager.track(impressions_decorator) unless impressions_decorator.nil?
338336
treatments
339337
end
340338

341339
def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple = false)
342-
impressions = []
340+
impressions_decorator = []
343341
begin
344342
start = Time.now
345343
if feature_flag.nil? && ready?
346344
@config.logger.warn("#{calling_method}: you passed #{feature_flag_name} that " \
347345
'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
349347
end
350-
treatment_data =
348+
351349
if !feature_flag.nil? && ready?
352-
@evaluator.evaluate_feature_flag(
350+
treatment_data = @evaluator.evaluate_feature_flag(
353351
{ bucketing_key: bucketing_key, matching_key: matching_key }, feature_flag, attributes
354352
)
353+
impressions_disabled = feature_flag[:impressionsDisabled]
355354
else
356355
@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
358358
end
359359

360360
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, params={ attributes: attributes, time: nil }), :disabled => impressions_disabled }
362+
impressions_decorator << impression_decorator unless impression_decorator.nil?
363363
rescue StandardError => e
364364
@config.log_found_exception(__method__.to_s, e)
365-
366365
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?
367368

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
372370
end
373371

374-
return parsed_treatment(treatment_data, multiple), impressions
372+
return parsed_treatment(treatment_data, multiple), impressions_decorator
375373
end
376374

377375
def control_treatment
378-
{ treatment: Engine::Models::Treatment::CONTROL }
376+
{ :treatment => Engine::Models::Treatment::CONTROL }
379377
end
380378

381379
def control_treatment_with_config

lib/splitclient-rb/engine/common/impressions_manager.rb

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,16 @@ def initialize(config,
1818
@unique_keys_tracker = unique_keys_tracker
1919
end
2020

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])
2423
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
2925
@impression_counter.inc(split_name, impression_data[:m])
3026
@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)
3129
else # In OPTIMIZED mode we should track the total amount of evaluations and deduplicate the impressions.
3230
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
33-
3431
@impression_counter.inc(split_name, impression_data[:m]) unless impression_data[:pt].nil?
3532
end
3633
rescue StandardError => e
@@ -40,24 +37,24 @@ def build_impression(matching_key, bucketing_key, split_name, treatment, params
4037
impression(impression_data, params[:attributes])
4138
end
4239

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+
if @config.impressions_mode == :debug
49+
track_debug_mode([impression_decorator[:impression]], stats)
50+
else
51+
track_optimized_mode([impression_decorator[:impression]], stats)
52+
end
53+
rescue StandardError => e
54+
@config.log_found_exception(__method__.to_s, e)
55+
ensure
56+
record_stats(stats)
5557
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)
6158
end
6259
end
6360

@@ -126,11 +123,10 @@ def track_debug_mode(impressions, stats)
126123

127124
def track_optimized_mode(impressions, stats)
128125
optimized_impressions = impressions.select { |imp| should_queue_impression?(imp[:i]) }
129-
126+
stats[:dedupe] = impressions.length - optimized_impressions.length
130127
return if optimized_impressions.empty?
131128

132129
stats[:dropped] = @impressions_repository.add_bulk(optimized_impressions)
133-
stats[:dedupe] = impressions.length - optimized_impressions.length
134130
stats[:queued] = optimized_impressions.length - stats[:dropped]
135131
end
136132
end

lib/splitclient-rb/engine/synchronizer.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def start_periodic_data_recording
4848
events_sender
4949
start_telemetry_sync_task
5050
end
51-
51+
5252
impressions_count_sender
5353
start_unique_keys_tracker_task
5454
end
@@ -175,7 +175,7 @@ def attempt_splits_sync(target_cn, fetch_options, max_retries, retry_delay_secon
175175

176176
# Starts thread which loops constantly and sends impressions to the Split API
177177
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
179179
end
180180

181181
# Starts thread which loops constantly and sends events to the Split API
@@ -185,7 +185,7 @@ def events_sender
185185

186186
# Starts thread which loops constantly and sends impressions count to the Split API
187187
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
189189
end
190190

191191
def start_telemetry_sync_task
@@ -203,7 +203,7 @@ def sync_result(success, remaining_attempts, segment_names = nil)
203203
def sync_splits_and_segments
204204
@config.logger.debug('Synchronizing feature flags and segments ...') if @config.debug_enabled
205205
splits_result = @split_fetcher.fetch_splits
206-
206+
207207
splits_result[:success] && @segment_fetcher.fetch_segments
208208
end
209209
end

lib/splitclient-rb/helpers/repository_helper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ def self.update_feature_flag_repository(feature_flag_repository, feature_flags,
1313
next
1414
end
1515

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+
1623
config.logger.debug("storing feature flag (#{feature_flag[:name]})") if config.debug_enabled
1724
to_add.push(feature_flag)
1825
end

lib/splitclient-rb/split_factory.rb

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,33 +230,22 @@ def build_telemetry_synchronizer(flag_sets, flag_sets_invalid)
230230
end
231231

232232
def build_unique_keys_tracker
233-
if @config.impressions_mode != :none
234-
@unique_keys_tracker = Engine::Impressions::NoopUniqueKeysTracker.new
235-
return
236-
end
237-
238233
bf = Cache::Filter::BloomFilter.new(30_000_000)
239234
filter_adapter = Cache::Filter::FilterAdapter.new(@config, bf)
240235
cache = Concurrent::Hash.new
241236
@unique_keys_tracker = Engine::Impressions::UniqueKeysTracker.new(@config, filter_adapter, @impressions_sender_adapter, cache)
242237
end
243238

244239
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)
247241
@impression_observer = Observers::NoopImpressionObserver.new
248242
else
249243
@impression_observer = Observers::ImpressionObserver.new
250244
end
251245
end
252246

253247
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
260249
end
261250

262251
def build_impressions_sender_adapter

spec/cache/repositories/impressions_repository_spec.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
it 'adds impressions' do
5656
params = { attributes: {}, time: 1_478_113_516_002 }
5757
impressions = []
58-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, params)
59-
impressions << impressions_manager.build_impression('matching_key1', nil, :bar, treatment2, params)
58+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, false, params), :disabled => false }
59+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :bar, treatment2, false, params), :disabled => false }
6060
impressions_manager.track(impressions)
6161

6262
expect(repository.batch).to match_array(result)
@@ -67,8 +67,8 @@
6767
it 'adds impressions in bulk' do
6868
params = { attributes: {}, time: 1_478_113_516_002 }
6969
impressions = []
70-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, params)
71-
impressions << impressions_manager.build_impression('matching_key1', nil, :bar, treatment2, params)
70+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, false, params), :disabled => false }
71+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :bar, treatment2, false, params), :disabled => false }
7272
impressions_manager.track(impressions)
7373

7474
expect(repository.batch).to match_array(result)
@@ -80,7 +80,7 @@
8080
config.labels_enabled = false
8181
params = { attributes: {}, time: 1_478_113_516_002 }
8282
impressions = []
83-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, params)
83+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, false, params), :disabled => false }
8484
impressions_manager.track(impressions)
8585

8686
expect(repository.batch.first[:i][:r]).to be_nil
@@ -89,8 +89,8 @@
8989
it 'bulk size less than the actual queue' do
9090
params = { attributes: {}, time: 1_478_113_516_002 }
9191
impressions = []
92-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, params)
93-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo, treatment2, params)
92+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo, treatment1, false, params), :disabled => false }
93+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo, treatment2, false, params), :disabled => false }
9494
impressions_manager.track(impressions)
9595

9696
config.impressions_bulk_size = 1
@@ -142,8 +142,8 @@
142142
treatment = { treatment: 'on', label: 'sample_rule', change_number: 1_533_177_602_748 }
143143
params = { attributes: {}, time: 1_478_113_516_002 }
144144
impressions = []
145-
impressions << impressions_manager.build_impression('matching_key1', nil, :foo1, treatment, params)
146-
impressions << impressions_manager.build_impression('matching_key2', nil, :foo1, treatment, params)
145+
impressions << { :impression => impressions_manager.build_impression('matching_key1', nil, :foo1, treatment, false, params), :disabled => false }
146+
impressions << { :impression => impressions_manager.build_impression('matching_key2', nil, :foo1, treatment, false, params), :disabled => false }
147147
impressions_manager.track(impressions)
148148

149149
expect(repository.batch.size).to eq(1)
@@ -200,8 +200,8 @@
200200
expect(config.impressions_adapter).to receive(:expire).once.with(anything, 3600)
201201
params = { attributes: {}, time: 1_478_113_516_002 }
202202
impressions = []
203-
impressions << impressions_manager.build_impression('matching_key', nil, :foo1, treatment, params)
204-
impressions << impressions_manager.build_impression('matching_key', nil, :foo1, treatment, params)
203+
impressions << { :impression => impressions_manager.build_impression('matching_key', nil, :foo1, treatment, false, params), :disabled => false }
204+
impressions << { :impression => impressions_manager.build_impression('matching_key', nil, :foo1, treatment, false, params), :disabled => false }
205205
impressions_manager.track(impressions)
206206
end
207207

@@ -211,7 +211,7 @@
211211

212212
params = { attributes: {}, time: 1_478_113_516_002 }
213213
impressions = []
214-
impressions << impressions_manager.build_impression('matching_key', nil, :foo1, treatment, params)
214+
impressions << { :impression => impressions_manager.build_impression('matching_key', nil, :foo1, treatment, false, params), :disabled => false }
215215
impressions_manager.track(impressions)
216216

217217
expect(repository.batch).to eq([])
@@ -221,8 +221,8 @@
221221
other_treatment = { treatment: 'on', label: 'sample_rule_2', change_number: 1_533_177_602_748 }
222222
params = { attributes: {}, time: 1_478_113_516_002 }
223223
impressions = []
224-
impressions << impressions_manager.build_impression('matching_key', nil, :foo1, treatment, params)
225-
impressions << impressions_manager.build_impression('matching_key', nil, :foo2, other_treatment, params)
224+
impressions << { :impression => impressions_manager.build_impression('matching_key', nil, :foo1, treatment, false, params), :disabled => false }
225+
impressions << { :impression => impressions_manager.build_impression('matching_key', nil, :foo2, other_treatment, false, params), :disabled => false }
226226
impressions_manager.track(impressions)
227227

228228
adapter.get_from_queue('SPLITIO.impressions', 0).map do |e|
@@ -252,8 +252,8 @@
252252

253253
params = { attributes: {}, time: 1_478_113_516_002 }
254254
impressions = []
255-
impressions << custom_impressions_manager.build_impression('matching_key', nil, :foo1, treatment, params)
256-
impressions << custom_impressions_manager.build_impression('matching_key', nil, :foo2, other_treatment, params)
255+
impressions << { :impression => custom_impressions_manager.build_impression('matching_key', nil, :foo1, treatment, false, params), :disabled => false }
256+
impressions << { :impression => custom_impressions_manager.build_impression('matching_key', nil, :foo2, other_treatment, false, params), :disabled => false }
257257
custom_impressions_manager.track(impressions)
258258

259259
custom_adapter.get_from_queue('SPLITIO.impressions', 0).map do |e|

0 commit comments

Comments
 (0)