Skip to content

Commit f122208

Browse files
authored
Merge pull request #568 from splitio/FME-4374-imp-prop-options-class
Created EvaluationOptions class
2 parents 2d7d41d + 897c28f commit f122208

File tree

8 files changed

+85
-58
lines changed

8 files changed

+85
-58
lines changed

lib/splitclient-rb.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
require 'splitclient-rb/engine/models/segment_type'
110110
require 'splitclient-rb/engine/models/treatment'
111111
require 'splitclient-rb/engine/models/split_http_response'
112+
require 'splitclient-rb/engine/models/evaluation_options'
112113
require 'splitclient-rb/engine/auth_api_client'
113114
require 'splitclient-rb/engine/back_off'
114115
require 'splitclient-rb/engine/push_manager'

lib/splitclient-rb/clients/split_client.rb

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,64 +35,64 @@ def initialize(sdk_key, repositories, status_manager, config, impressions_manage
3535
end
3636

3737
def get_treatment(
38-
key, split_name, attributes = {}, options = nil, split_data = nil, store_impressions = true,
38+
key, split_name, attributes = {}, evaluation_options = nil, split_data = nil, store_impressions = true,
3939
multiple = false, evaluator = nil
4040
)
41-
result = treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT, multiple, options)
41+
result = treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT, multiple, evaluation_options)
4242
return result.tap { |t| t.delete(:config) } if multiple
4343
result[:treatment]
4444
end
4545

4646
def get_treatment_with_config(
47-
key, split_name, attributes = {}, options = nil, split_data = nil, store_impressions = true,
47+
key, split_name, attributes = {}, evaluation_options = nil, split_data = nil, store_impressions = true,
4848
multiple = false, evaluator = nil
4949
)
50-
treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT_WITH_CONFIG, multiple, options)
50+
treatment(key, split_name, attributes, split_data, store_impressions, GET_TREATMENT_WITH_CONFIG, multiple, evaluation_options)
5151
end
5252

53-
def get_treatments(key, split_names, attributes = {}, options = nil)
54-
treatments = treatments(key, split_names, attributes, options)
53+
def get_treatments(key, split_names, attributes = {}, evaluation_options = nil)
54+
treatments = treatments(key, split_names, attributes, evaluation_options)
5555

5656
return treatments if treatments.nil?
5757
keys = treatments.keys
5858
treats = treatments.map { |_,t| t[:treatment] }
5959
Hash[keys.zip(treats)]
6060
end
6161

62-
def get_treatments_with_config(key, split_names, attributes = {}, options = nil)
63-
treatments(key, split_names, attributes, options, GET_TREATMENTS_WITH_CONFIG)
62+
def get_treatments_with_config(key, split_names, attributes = {}, evaluation_options = nil)
63+
treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG)
6464
end
6565

66-
def get_treatments_by_flag_set(key, flag_set, attributes = {}, options = nil)
66+
def get_treatments_by_flag_set(key, flag_set, attributes = {}, evaluation_options = nil)
6767
valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_BY_FLAG_SET, [flag_set])
6868
split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
69-
treatments = treatments(key, split_names, attributes, options, GET_TREATMENTS_BY_FLAG_SET)
69+
treatments = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_BY_FLAG_SET)
7070
return treatments if treatments.nil?
7171
keys = treatments.keys
7272
treats = treatments.map { |_,t| t[:treatment] }
7373
Hash[keys.zip(treats)]
7474
end
7575

76-
def get_treatments_by_flag_sets(key, flag_sets, attributes = {}, options = nil)
76+
def get_treatments_by_flag_sets(key, flag_sets, attributes = {}, evaluation_options = nil)
7777
valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_BY_FLAG_SETS, flag_sets)
7878
split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
79-
treatments = treatments(key, split_names, attributes, options, GET_TREATMENTS_BY_FLAG_SETS)
79+
treatments = treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_BY_FLAG_SETS)
8080
return treatments if treatments.nil?
8181
keys = treatments.keys
8282
treats = treatments.map { |_,t| t[:treatment] }
8383
Hash[keys.zip(treats)]
8484
end
8585

86-
def get_treatments_with_config_by_flag_set(key, flag_set, attributes = {}, options = nil)
86+
def get_treatments_with_config_by_flag_set(key, flag_set, attributes = {}, evaluation_options = nil)
8787
valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, [flag_set])
8888
split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
89-
treatments(key, split_names, attributes, options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET)
89+
treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET)
9090
end
9191

92-
def get_treatments_with_config_by_flag_sets(key, flag_sets, attributes = {}, options = nil)
92+
def get_treatments_with_config_by_flag_sets(key, flag_sets, attributes = {}, evaluation_options = nil)
9393
valid_flag_set = @split_validator.valid_flag_sets(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, flag_sets)
9494
split_names = @splits_repository.get_feature_flags_by_sets(valid_flag_set)
95-
treatments(key, split_names, attributes, options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS)
95+
treatments(key, split_names, attributes, evaluation_options, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS)
9696
end
9797

9898
def destroy
@@ -235,18 +235,14 @@ def validate_properties(properties, method = 'Event')
235235
return fixed_properties, size
236236
end
237237

238-
def validate_options(options)
239-
if !options.is_a?(Hash)
240-
@config.logger.warn("Option #{options} should be a hash type. Setting value to nil")
238+
def validate_evaluation_options(evaluation_options)
239+
if !evaluation_options.is_a?(SplitIoClient::Engine::Models::EvaluationOptions)
240+
@config.logger.warn("Option #{evaluation_options} should be a EvaluationOptions type. Setting value to nil")
241241
return nil, 0
242242
end
243-
options = options.transform_keys(&:to_sym)
244-
if !options.key?(:properties)
245-
@config.logger.warn("Option #{options} hash does not contain properties key. Setting value to nil")
246-
return nil, 0
247-
end
248-
options[:properties], size = validate_properties(options[:properties], method = 'Treatment')
249-
return options, size
243+
evaluation_options.properties = evaluation_options.properties.transform_keys(&:to_sym)
244+
evaluation_options.properties, size = validate_properties(evaluation_options.properties, method = 'Treatment')
245+
return evaluation_options, size
250246
end
251247

252248
def valid_client
@@ -257,7 +253,7 @@ def valid_client
257253
@config.valid_mode
258254
end
259255

260-
def treatments(key, feature_flag_names, attributes = {}, options = nil, calling_method = 'get_treatments')
256+
def treatments(key, feature_flag_names, attributes = {}, evaluation_options = nil, calling_method = 'get_treatments')
261257
sanitized_feature_flag_names = sanitize_split_names(calling_method, feature_flag_names)
262258

263259
if sanitized_feature_flag_names.nil?
@@ -290,7 +286,7 @@ def treatments(key, feature_flag_names, attributes = {}, options = nil, calling_
290286
to_return[name.to_sym] = control_treatment_with_config
291287
impressions << { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, name.to_sym,
292288
control_treatment_with_config.merge({ :label => Engine::Models::Label::NOT_READY }), false, { attributes: attributes, time: nil },
293-
options), :disabled => false }
289+
evaluation_options), :disabled => false }
294290
}
295291
@impressions_manager.track(impressions)
296292
return to_return
@@ -312,7 +308,7 @@ def treatments(key, feature_flag_names, attributes = {}, options = nil, calling_
312308
invalid_treatments[key] = control_treatment_with_config
313309
next
314310
end
315-
treatments_labels_change_numbers, impressions = evaluate_treatment(feature_flag, key, bucketing_key, matching_key, attributes, calling_method, false, options)
311+
treatments_labels_change_numbers, impressions = evaluate_treatment(feature_flag, key, bucketing_key, matching_key, attributes, calling_method, false, evaluation_options)
316312
treatments[key] =
317313
{
318314
treatment: treatments_labels_change_numbers[:treatment],
@@ -335,7 +331,7 @@ def treatments(key, feature_flag_names, attributes = {}, options = nil, calling_
335331
# @param store_impressions [Boolean] impressions aren't stored if this flag is false
336332
# @return [String/Hash] Treatment as String or Hash of treatments in case of array of features
337333
def treatment(key, feature_flag_name, attributes = {}, split_data = nil, store_impressions = true,
338-
calling_method = 'get_treatment', multiple = false, options = nil)
334+
calling_method = 'get_treatment', multiple = false, evaluation_options = nil)
339335
impressions = []
340336
bucketing_key, matching_key = keys_from_key(key)
341337

@@ -353,13 +349,13 @@ def treatment(key, feature_flag_name, attributes = {}, split_data = nil, store_i
353349
end
354350

355351
feature_flag = @splits_repository.get_split(feature_flag_name)
356-
treatments, impressions_decorator = evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple, options)
352+
treatments, impressions_decorator = evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple, evaluation_options)
357353

358354
@impressions_manager.track(impressions_decorator) unless impressions_decorator.nil?
359355
treatments
360356
end
361357

362-
def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple = false, options = nil)
358+
def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_key, attributes, calling_method, multiple = false, evaluation_options = nil)
363359
impressions_decorator = []
364360
begin
365361
start = Time.now
@@ -380,16 +376,16 @@ def evaluate_treatment(feature_flag, feature_flag_name, bucketing_key, matching_
380376
impressions_disabled = false
381377
end
382378

383-
options, size = validate_options(options) unless options.nil?
384-
options[:properties] = nil unless options.nil? or check_properties_size((EVENT_AVERAGE_SIZE + size), "Properties are ignored")
379+
evaluation_options, size = validate_evaluation_options(evaluation_options) unless evaluation_options.nil?
380+
evaluation_options.properties = nil unless evaluation_options.nil? or check_properties_size((EVENT_AVERAGE_SIZE + size), "Properties are ignored")
385381

386382
record_latency(calling_method, start)
387-
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, treatment_data, impressions_disabled, { attributes: attributes, time: nil }, options), :disabled => impressions_disabled }
383+
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, treatment_data, impressions_disabled, { attributes: attributes, time: nil }, evaluation_options), :disabled => impressions_disabled }
388384
impressions_decorator << impression_decorator unless impression_decorator.nil?
389385
rescue StandardError => e
390386
@config.log_found_exception(__method__.to_s, e)
391387
record_exception(calling_method)
392-
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, control_treatment, false, { attributes: attributes, time: nil }, options), :disabled => false }
388+
impression_decorator = { :impression => @impressions_manager.build_impression(matching_key, bucketing_key, feature_flag_name, control_treatment, false, { attributes: attributes, time: nil }, evaluation_options), :disabled => false }
393389
impressions_decorator << impression_decorator unless impression_decorator.nil?
394390

395391
return parsed_treatment(control_treatment.merge({ :label => Engine::Models::Label::EXCEPTION }), multiple), impressions_decorator

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

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,23 @@ def initialize(config,
1919
end
2020

2121
def build_impression(matching_key, bucketing_key, split_name, treatment_data, impressions_disabled, params = {},
22-
options = nil)
23-
properties = options.nil? ? nil : options[:properties]
22+
evaluation_options = nil)
23+
properties = get_properties(evaluation_options)
2424
impression_data = impression_data(matching_key, bucketing_key, split_name, treatment_data, params[:time], properties)
25+
return impression(impression_data, params[:attributes]) if check_return_conditions(properties)
26+
2527
begin
26-
if @config.impressions_mode == :none || impressions_disabled
28+
if check_none_mode(impressions_disabled)
2729
@impression_counter.inc(split_name, impression_data[:m])
2830
@unique_keys_tracker.track(split_name, matching_key)
29-
elsif @config.impressions_mode == :debug # In DEBUG mode we should calculate the pt only.
30-
return impression(impression_data, params[:attributes]) unless properties.nil?
31-
32-
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
33-
else # In OPTIMIZED mode we should track the total amount of evaluations and deduplicate the impressions.
34-
return impression(impression_data, params[:attributes]) unless properties.nil?
35-
31+
end
32+
if check_observe_impressions
33+
# In DEBUG mode we should calculate the pt only.
3634
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
37-
@impression_counter.inc(split_name, impression_data[:m]) unless impression_data[:pt].nil?
35+
end
36+
if check_impression_counter(impression_data)
37+
# In OPTIMIZED mode we should track the total amount of evaluations and deduplicate the impressions.
38+
@impression_counter.inc(split_name, impression_data[:m])
3839
end
3940
rescue StandardError => e
4041
@config.log_found_exception(__method__.to_s, e)
@@ -67,6 +68,26 @@ def track(impressions_decorator)
6768

6869
private
6970

71+
def check_return_conditions(properties)
72+
return (@config.impressions_mode == :debug || @config.impressions_mode == :optimized) && !properties.nil?
73+
end
74+
75+
def check_none_mode(impressions_disabled)
76+
return @config.impressions_mode == :none || impressions_disabled
77+
end
78+
79+
def check_observe_impressions
80+
return @config.impressions_mode == :debug || @config.impressions_mode == :optimized
81+
end
82+
83+
def check_impression_counter(impression_data)
84+
return @config.impressions_mode == :optimized && !impression_data[:pt].nil?
85+
end
86+
87+
def get_properties(evaluation_options)
88+
return evaluation_options.nil? ? nil : evaluation_options.properties
89+
end
90+
7091
def impression_router
7192
@impression_router ||= SplitIoClient::ImpressionRouter.new(@config)
7293
rescue StandardError => e
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module SplitIoClient::Engine::Models
2+
class EvaluationOptions
3+
attr_accessor :properties
4+
5+
def initialize(properties)
6+
@properties = properties
7+
end
8+
end
9+
end

spec/cache/senders/impressions_formatter_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
it 'formats multiple impressions for one key' do
7676
params = { attributes: {}, time: 1_478_113_518_900 }
7777
impressions = []
78-
impressions << { :impression => impressions_manager.build_impression('matching_key3', nil, 'foo2', treatment3, false, params, {:properties => {:prop => "val"}}), :disabled => false }
78+
impressions << { :impression => impressions_manager.build_impression('matching_key3', nil, 'foo2', treatment3, false, params, SplitIoClient::Engine::Models::EvaluationOptions.new({:prop => "val"})), :disabled => false }
7979
impressions_manager.track(impressions)
8080

8181
expect(formatted_impressions.find { |i| i[:f] == :foo1 }[:i]).to match_array(

spec/cache/senders/impressions_sender_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
params2 = { attributes: {}, time: 1_478_113_518_285 }
4747
impressions = []
4848
impressions << { :impression => impressions_manager.build_impression('matching_key', 'foo1', 'foo1', treatment1, false, params), :disabled => false }
49-
impressions << { :impression => impressions_manager.build_impression('matching_key2', 'foo2', 'foo2', treatment2, false, params2, {:properties => {:prop => "val"}}), :disabled => false }
49+
impressions << { :impression => impressions_manager.build_impression('matching_key2', 'foo2', 'foo2', treatment2, false, params2, SplitIoClient::Engine::Models::EvaluationOptions.new({:prop => "val"})), :disabled => false }
5050
impressions_manager.track(impressions)
5151
end
5252

spec/engine/common/impression_manager_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
'split_name_test',
7373
treatment,
7474
false,
75-
params, {"properties": {"prop":"val"}})
75+
params, SplitIoClient::Engine::Models::EvaluationOptions.new({"prop":"val"}))
7676
expect(impression).to match(expected)
7777

7878
result_count = impression_counter.pop_all

0 commit comments

Comments
 (0)