@@ -35,7 +35,7 @@ def initialize(logger)
3535 @bucket_seed = HASH_SEED
3636 end
3737
38- def bucket ( project_config , experiment , bucketing_id , user_id , decide_reasons = nil )
38+ def bucket ( project_config , experiment , bucketing_id , user_id )
3939 # Determines ID of variation to be shown for a given experiment key and user ID.
4040 #
4141 # project_config - Instance of ProjectConfig
@@ -44,7 +44,9 @@ def bucket(project_config, experiment, bucketing_id, user_id, decide_reasons = n
4444 # user_id - String ID for user.
4545 #
4646 # Returns variation in which visitor with ID user_id has been placed. Nil if no variation.
47- return nil if experiment . nil?
47+ return nil , [ ] if experiment . nil?
48+
49+ decide_reasons = [ ]
4850
4951 # check if experiment is in a group; if so, check if user is bucketed into specified experiment
5052 # this will not affect evaluation of rollout rules.
@@ -55,72 +57,77 @@ def bucket(project_config, experiment, bucketing_id, user_id, decide_reasons = n
5557 group = project_config . group_id_map . fetch ( group_id )
5658 if Helpers ::Group . random_policy? ( group )
5759 traffic_allocations = group . fetch ( 'trafficAllocation' )
58- bucketed_experiment_id = find_bucket ( bucketing_id , user_id , group_id , traffic_allocations )
60+ bucketed_experiment_id , find_bucket_reasons = find_bucket ( bucketing_id , user_id , group_id , traffic_allocations )
61+ decide_reasons . push ( *find_bucket_reasons )
62+
5963 # return if the user is not bucketed into any experiment
6064 unless bucketed_experiment_id
6165 message = "User '#{ user_id } ' is in no experiment."
6266 @logger . log ( Logger ::INFO , message )
63- decide_reasons & .push ( message )
64- return nil
67+ decide_reasons . push ( message )
68+ return nil , decide_reasons
6569 end
6670
6771 # return if the user is bucketed into a different experiment than the one specified
6872 if bucketed_experiment_id != experiment_id
6973 message = "User '#{ user_id } ' is not in experiment '#{ experiment_key } ' of group #{ group_id } ."
7074 @logger . log ( Logger ::INFO , message )
71- decide_reasons & .push ( message )
72- return nil
75+ decide_reasons . push ( message )
76+ return nil , decide_reasons
7377 end
7478
7579 # continue bucketing if the user is bucketed into the experiment specified
7680 message = "User '#{ user_id } ' is in experiment '#{ experiment_key } ' of group #{ group_id } ."
7781 @logger . log ( Logger ::INFO , message )
78- decide_reasons & .push ( message )
82+ decide_reasons . push ( message )
7983 end
8084 end
8185
8286 traffic_allocations = experiment [ 'trafficAllocation' ]
83- variation_id = find_bucket ( bucketing_id , user_id , experiment_id , traffic_allocations , decide_reasons )
87+ variation_id , find_bucket_reasons = find_bucket ( bucketing_id , user_id , experiment_id , traffic_allocations )
88+ decide_reasons . push ( *find_bucket_reasons )
89+
8490 if variation_id && variation_id != ''
8591 variation = project_config . get_variation_from_id ( experiment_key , variation_id )
86- return variation
92+ return variation , decide_reasons
8793 end
8894
8995 # Handle the case when the traffic range is empty due to sticky bucketing
9096 if variation_id == ''
9197 message = 'Bucketed into an empty traffic range. Returning nil.'
9298 @logger . log ( Logger ::DEBUG , message )
93- decide_reasons & .push ( message )
99+ decide_reasons . push ( message )
94100 end
95101
96- nil
102+ [ nil , decide_reasons ]
97103 end
98104
99- def find_bucket ( bucketing_id , user_id , parent_id , traffic_allocations , decide_reasons = nil )
105+ def find_bucket ( bucketing_id , user_id , parent_id , traffic_allocations )
100106 # Helper function to find the matching entity ID for a given bucketing value in a list of traffic allocations.
101107 #
102108 # bucketing_id - String A customer-assigned value user to generate bucketing key
103109 # user_id - String ID for user
104110 # parent_id - String entity ID to use for bucketing ID
105111 # traffic_allocations - Array of traffic allocations
106112 #
107- # Returns entity ID corresponding to the provided bucket value or nil if no match is found.
113+ # Returns and array of two values where first value is the entity ID corresponding to the provided bucket value
114+ # or nil if no match is found. The second value contains the array of reasons stating how the deicision was taken
115+ decide_reasons = [ ]
108116 bucketing_key = format ( BUCKETING_ID_TEMPLATE , bucketing_id : bucketing_id , entity_id : parent_id )
109117 bucket_value = generate_bucket_value ( bucketing_key )
110118
111119 message = "Assigned bucket #{ bucket_value } to user '#{ user_id } ' with bucketing ID: '#{ bucketing_id } '."
112120 @logger . log ( Logger ::DEBUG , message )
113- decide_reasons &.push ( message )
114121
115122 traffic_allocations . each do |traffic_allocation |
116123 current_end_of_range = traffic_allocation [ 'endOfRange' ]
117124 if bucket_value < current_end_of_range
118125 entity_id = traffic_allocation [ 'entityId' ]
119- return entity_id
126+ return entity_id , decide_reasons
120127 end
121128 end
122129
123- nil
130+ [ nil , decide_reasons ]
124131 end
125132
126133 private
0 commit comments