Class: DecisionUtil

Inherits:
Object
  • Object
show all
Defined in:
lib/wingify/utils/decision_util.rb

Class Method Summary collapse

Class Method Details

.check_campaign_whitelisting(campaign, context) ⇒ Object

Check if the campaign satisfies whitelisting

Parameters:



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/wingify/utils/decision_util.rb', line 198

def self.check_campaign_whitelisting(campaign, context)
  # Check if the campaign satisfies whitelisting
  whitelisting_result = evaluate_whitelisting(campaign, context)
  status = whitelisting_result ? StatusEnum::PASSED : StatusEnum::FAILED
  variation_string = whitelisting_result ? whitelisting_result[:variation].get_key : ''

  LoggerService.log(LogLevelEnum::INFO, "WHITELISTING_STATUS", {
    userId: context.get_id,
    campaignKey: campaign.get_type == CampaignTypeEnum::AB ? campaign.get_key : "#{campaign.get_name}_#{campaign.get_rule_key}",
    status: status,
    variationString: variation_string
  })

  whitelisting_result
end

.check_whitelisting_and_pre_seg(settings, feature, campaign, context, evaluated_feature_map, meg_group_winner_campaigns, storage_service, decision) ⇒ Object

Check if the campaign satisfies whitelisting and pre-segmentation

Parameters:

  • settings (SettingsModel)

    The settings for the VWO instance

  • feature (FeatureModel)

    The feature to evaluate

  • campaign (CampaignModel)

    The campaign to evaluate

  • context (ContextModel)

    The context for the evaluation

  • evaluated_feature_map (Hash)

    The map of evaluated features

  • meg_group_winner_campaigns (Hash)

    The map of MEG group winner campaigns



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/wingify/utils/decision_util.rb', line 44

def self.check_whitelisting_and_pre_seg(settings, feature, campaign, context, evaluated_feature_map, meg_group_winner_campaigns, storage_service, decision)
  vwo_user_id = UUIDUtil.get_uuid(context.get_id, settings.)
  campaign_id = campaign.get_id

  if campaign.get_type == CampaignTypeEnum::AB
    # Set _vwoUserId for variation targeting variables
    variation_targeting_vars = context.get_variation_targeting_variables || {}
    variation_targeting_vars["_vwoUserId"] = campaign.get_is_user_list_enabled ? vwo_user_id : context.get_id
    context.set_variation_targeting_variables(variation_targeting_vars)
    decision[:variation_targeting_variables] = variation_targeting_vars

    # Check for whitelisting
    if campaign.get_is_forced_variation_enabled
      whitelisted_variation = check_campaign_whitelisting(campaign, context)
      return [true, whitelisted_variation] if whitelisted_variation && !whitelisted_variation.empty?
    else
      LoggerService.log(LogLevelEnum::INFO, "WHITELISTING_SKIP", {
        campaignKey: campaign.get_rule_key,
        userId: context.get_id
      })
    end
  end

  # User list segment check for campaign pre-segmentation
  custom_vars = context.get_custom_variables || {}
  custom_vars["_vwoUserId"] = campaign.get_is_user_list_enabled ? vwo_user_id : context.get_id
  context.set_custom_variables(custom_vars)
  decision[:custom_variables] = custom_vars

  # Check if rule belongs to Mutually Exclusive Group (MEG)
  group_details = CampaignUtil.get_group_details_if_campaign_part_of_it(settings, campaign_id, campaign.get_type == CampaignTypeEnum::PERSONALIZE ? campaign.get_variations[0].get_id : nil)
  group_id = group_details[:group_id]

  # Check if the group has already been evaluated
  group_winner_campaign_id = meg_group_winner_campaigns[group_id] if meg_group_winner_campaigns && meg_group_winner_campaigns.key?(group_id)
  return evaluate_meg_campaign(group_winner_campaign_id, campaign, context, meg_group_winner_campaigns, group_id) if group_winner_campaign_id

  # Check in storage if the group was already evaluated
  stored_data = StorageDecorator.new.get_feature_from_storage("#{Constants::VWO_META_MEG_KEY}#{group_id}", context, storage_service)
  if stored_data && stored_data[:experiment_key] && stored_data[:experiment_id]
    LoggerService.log(LogLevelEnum::INFO, "MEG_CAMPAIGN_FOUND_IN_STORAGE", {
      campaignKey: stored_data[:experiment_key],
      userId: context.get_id
    })

    if stored_data[:experiment_id] == campaign_id
      return evaluate_meg_personalization(campaign, stored_data, meg_group_winner_campaigns, group_id)
    end
    meg_group_winner_campaigns[group_id] = stored_data[:experiment_variation_id] != -1 ? "#{stored_data[:experiment_id]}_#{stored_data[:experiment_variation_id]}" : stored_data[:experiment_id]
    return [false, nil]
  end

  # Pre-segmentation check
  pre_segmentation_passed = CampaignDecisionService.new.get_pre_segmentation_decision(campaign, context)

  if pre_segmentation_passed && group_id
    winner_campaign = evaluate_groups(settings, feature, group_id, evaluated_feature_map, context, storage_service)
    return evaluate_meg_campaign_winner(winner_campaign, campaign, context, meg_group_winner_campaigns, group_id)
  end

  [pre_segmentation_passed, nil]
end

.evaluate_meg_campaign(group_winner_campaign_id, campaign, context, meg_group_winner_campaigns, group_id) ⇒ Object

Evaluate the MEG campaign

Parameters:

  • group_winner_campaign_id (String)

    The ID of the MEG group winner campaign

  • campaign (CampaignModel)

    The campaign to evaluate

  • context (ContextModel)

    The context for the evaluation

  • meg_group_winner_campaigns (Hash)

    The map of MEG group winner campaigns

  • group_id (String)

    The ID of the MEG group



113
114
115
116
117
118
119
120
# File 'lib/wingify/utils/decision_util.rb', line 113

def self.evaluate_meg_campaign(group_winner_campaign_id, campaign, context, meg_group_winner_campaigns, group_id)
  if campaign.get_type == CampaignTypeEnum::AB && group_winner_campaign_id == campaign.get_id
    return [true, nil]
  elsif campaign.get_type == CampaignTypeEnum::PERSONALIZE && group_winner_campaign_id == "#{campaign.get_id}_#{campaign.get_variations[0].get_id}"
    return [true, nil]
  end
  [false, nil]
end

.evaluate_meg_campaign_winner(winner_campaign, campaign, context, meg_group_winner_campaigns, group_id) ⇒ Object

Evaluate the MEG campaign winner

Parameters:

  • winner_campaign (CampaignModel)

    The winner campaign

  • campaign (CampaignModel)

    The campaign to evaluate

  • context (ContextModel)

    The context for the evaluation

  • meg_group_winner_campaigns (Hash)

    The map of MEG group winner campaigns

  • group_id (String)

    The ID of the MEG group



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/wingify/utils/decision_util.rb', line 141

def self.evaluate_meg_campaign_winner(winner_campaign, campaign, context, meg_group_winner_campaigns, group_id)
  if winner_campaign && winner_campaign.get_id == campaign.get_id
    if winner_campaign.get_type == CampaignTypeEnum::AB
      return [true, nil]
    else
      # if personalise then check if the requested variation is the winner
      if winner_campaign.get_variations[0].get_id == campaign.get_variations[0].get_id
        return [true, nil]
      else
        meg_group_winner_campaigns[group_id] = "#{winner_campaign.get_id}_#{winner_campaign.get_variations[0].get_id}"
        return [false, nil]
      end
    end
  elsif winner_campaign
    if winner_campaign.get_type == CampaignTypeEnum::AB
      meg_group_winner_campaigns[group_id] = winner_campaign.get_id
    else
      meg_group_winner_campaigns[group_id] = "#{winner_campaign.get_id}_#{winner_campaign.get_variations[0].get_id}"
    end
    return [false, nil]
  end
  
  meg_group_winner_campaigns[group_id] = -1
  [false, nil]
end

.evaluate_meg_personalization(campaign, stored_data, meg_group_winner_campaigns, group_id) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/wingify/utils/decision_util.rb', line 122

def self.evaluate_meg_personalization(campaign, stored_data, meg_group_winner_campaigns, group_id)
  if campaign.get_type == CampaignTypeEnum::PERSONALIZE
    if stored_data[:experiment_variation_id] == campaign.get_variations[0].get_id
      return [true, nil]
    else
      meg_group_winner_campaigns[group_id] = "#{stored_data[:experiment_id]}_#{stored_data[:experiment_variation_id]}"
      return [false, nil]
    end
  else
    return [true, nil]
  end
end

.evaluate_traffic_and_get_variation(settings, campaign, context) ⇒ Object

Evaluate the traffic and get the variation

Parameters:

  • settings (SettingsModel)

    The settings for the VWO instance

  • campaign (CampaignModel)

    The campaign to evaluate

  • user_id (String)

    The ID of the user



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/wingify/utils/decision_util.rb', line 171

def self.evaluate_traffic_and_get_variation(settings, campaign, context)
  variation = CampaignDecisionService.new.get_variation_alloted(context, settings., campaign)

  user_id = context.get_id
  bucketing_seed = context.get_bucketing_seed
  bucketing_id = bucketing_seed || user_id
  display_user_id = bucketing_id != user_id ? "#{user_id} (Seed: #{bucketing_id})" : user_id

  if variation.nil?
    LoggerService.log(LogLevelEnum::INFO, "USER_CAMPAIGN_BUCKET_INFO", {
      campaignKey: campaign.get_type == CampaignTypeEnum::AB ? campaign.get_key : "#{campaign.get_name}_#{campaign.get_rule_key}",
      userId: display_user_id,
      status: 'did not get any variation'
    })
    return nil
  end
  LoggerService.log(LogLevelEnum::INFO, "USER_CAMPAIGN_BUCKET_INFO", {
    campaignKey: campaign.get_type == CampaignTypeEnum::AB ? campaign.get_key : "#{campaign.get_name}_#{campaign.get_rule_key}",
    userId: display_user_id,
    status: "got variation: #{variation.get_key}"
  })
  variation
end

.evaluate_whitelisting(campaign, context) ⇒ Object

Evaluate the whitelisting

Parameters:



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/wingify/utils/decision_util.rb', line 217

def self.evaluate_whitelisting(campaign, context)
  targeted_variations = []
  
  campaign.get_variations.each do |variation|
    next if DataTypeUtil.is_object(variation.get_segments) && variation.get_segments.empty?
    if DataTypeUtil.is_object(variation.get_segments)
      segmentation_result = SegmentationManager.instance.validate_segmentation(
        variation.get_segments,
        context.get_variation_targeting_variables
      )

      targeted_variations.push(clone_object(variation)) if segmentation_result
    end
  end

  # Determine the whitelisted variation
  whitelisted_variation = nil
  if targeted_variations.length > 1
    scale_variation_weights(targeted_variations)
    current_allocation = 0

    targeted_variations.each do |variation|
      step_factor = assign_range_values(variation, current_allocation)
      current_allocation += step_factor
    end

    whitelisted_variation = CampaignDecisionService.new.get_variation(
      targeted_variations,
      DecisionMaker.new.calculate_bucket_value(CampaignUtil.get_bucketing_seed(context.get_bucketing_seed || context.get_id, campaign, nil))
    )
  else
    whitelisted_variation = targeted_variations.first
  end

  return nil unless whitelisted_variation

  {
    variation: whitelisted_variation,
    variation_name: whitelisted_variation.get_key,
    variation_id: whitelisted_variation.get_id
  }
end