Class: VWO::Core::VariationDecider
- Inherits:
-
Object
- Object
- VWO::Core::VariationDecider
- Includes:
- VWO::CONSTANTS, Enums, Utils::Campaign, Utils::UUID, Utils::Validations
- Defined in:
- lib/vwo/core/variation_decider.rb
Constant Summary collapse
- FILE =
FileNameEnum::VARIATION_DECIDER
Constants included from Utils::UUID
Constants included from VWO::CONSTANTS
VWO::CONSTANTS::API_VERSION, VWO::CONSTANTS::DEFAULT_EVENTS_PER_REQUEST, VWO::CONSTANTS::DEFAULT_REQUEST_TIME_INTERVAL, VWO::CONSTANTS::GOAL_TYPES, VWO::CONSTANTS::HTTPS_PROTOCOL, VWO::CONSTANTS::HTTP_PROTOCOL, VWO::CONSTANTS::LIBRARY_PATH, VWO::CONSTANTS::MAX_EVENTS_PER_REQUEST, VWO::CONSTANTS::MAX_RANGE, VWO::CONSTANTS::MAX_TRAFFIC_PERCENT, VWO::CONSTANTS::MAX_TRAFFIC_VALUE, VWO::CONSTANTS::MIN_EVENTS_PER_REQUEST, VWO::CONSTANTS::MIN_REQUEST_TIME_INTERVAL, VWO::CONSTANTS::PLATFORM, VWO::CONSTANTS::RUBY_VARIABLE_TYPES, VWO::CONSTANTS::SDK_NAME, VWO::CONSTANTS::SDK_VERSION, VWO::CONSTANTS::SEED_VALUE, VWO::CONSTANTS::STATUS_RUNNING, VWO::CONSTANTS::URL_NAMESPACE, VWO::CONSTANTS::VWO_DELIMITER
Instance Attribute Summary collapse
-
#has_stored_variation ⇒ Object
readonly
Returns the value of attribute has_stored_variation.
-
#hooks_manager ⇒ Object
readonly
Returns the value of attribute hooks_manager.
-
#user_storage_service ⇒ Object
readonly
Returns the value of attribute user_storage_service.
Instance Method Summary collapse
-
#add_variation_to_decision_properties(decision, campaign, variation) ⇒ Object
Add variation details to decision properties for hook manager.
- #campaign_not_activated?(user_id, campaign_key, api_name) ⇒ Boolean
-
#get_variation(user_id, campaign, api_name, campaign_key, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') ⇒ Object
Returns variation for the user for the passed campaign-key Check if Whitelisting is applicable, evaluate it, if any eligible variation is found,return, otherwise skip it Check in User Storage, if user found, validate variation and return Otherwise, proceed with variation assignment logic.
-
#get_variation_allotted(user_id, campaign, disable_logs = false) ⇒ Object
Returns the Variation Alloted for required campaign.
-
#get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision) ⇒ Object
Get variation by murmur logic if pre segmentation pass.
-
#get_variation_of_campaign_for_user(user_id, campaign, disable_logs = false) ⇒ Object
Assigns variation to a particular user depending on the campaign PercentTraffic.
- #initialize(settings_file, user_storage_service = nil, options = {}) ⇒ VariationDecider constructor
-
#initialize_decision_properties(user_id, campaign, api_name, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') ⇒ Object
Intitialize decision properties for hook manager.
- #meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign) ⇒ Boolean
-
#save_user_storage(user_id, campaign_key, _campaign_type, variation_name, goal_identifier, disable_logs = false) ⇒ Object
If UserStorageService is provided, save the assigned variation.
- #update_goal_identifier(user_id, campaign, variation, goal_identifier) ⇒ Object
Methods included from Utils::UUID
#generate, #generator_for, parse, uuid_v5
Methods included from Utils::Validations
#invalid_config_log, #valid_basic_data_type?, #valid_batch_event_settings, #valid_boolean?, #valid_config_log, #valid_goal?, #valid_hash?, #valid_number?, #valid_settings_file?, #valid_string?, #valid_value?, #validate_sdk_config?
Methods included from Utils::Campaign
#get_campaign_goal, #get_control_variation, #get_segments, #get_variable, #set_campaign_allocation, #set_variation_allocation
Constructor Details
#initialize(settings_file, user_storage_service = nil, options = {}) ⇒ VariationDecider
42 43 44 45 46 47 48 49 |
# File 'lib/vwo/core/variation_decider.rb', line 42 def initialize(settings_file, user_storage_service = nil, = {}) @logger = VWO::Utils::Logger @user_storage_service = user_storage_service @bucketer = VWO::Core::Bucketer.new @settings_file = settings_file @segment_evaluator = VWO::Services::SegmentEvaluator.new @hooks_manager = VWO::Services::HooksManager.new() end |
Instance Attribute Details
#has_stored_variation ⇒ Object (readonly)
Returns the value of attribute has_stored_variation.
28 29 30 |
# File 'lib/vwo/core/variation_decider.rb', line 28 def has_stored_variation @has_stored_variation end |
#hooks_manager ⇒ Object (readonly)
Returns the value of attribute hooks_manager.
28 29 30 |
# File 'lib/vwo/core/variation_decider.rb', line 28 def hooks_manager @hooks_manager end |
#user_storage_service ⇒ Object (readonly)
Returns the value of attribute user_storage_service.
28 29 30 |
# File 'lib/vwo/core/variation_decider.rb', line 28 def user_storage_service @user_storage_service end |
Instance Method Details
#add_variation_to_decision_properties(decision, campaign, variation) ⇒ Object
289 290 291 292 293 294 295 296 |
# File 'lib/vwo/core/variation_decider.rb', line 289 def add_variation_to_decision_properties(decision, campaign, variation) if campaign['type'] == CampaignTypes::VISUAL_AB || campaign['type'] == CampaignTypes::FEATURE_TEST decision[:variation_name] = variation['name'] decision[:variation_id] = variation['id'] end decision[:is_feature_enabled] = variation['isFeatureEnabled'] if campaign['type'] == CampaignTypes::FEATURE_TEST decision end |
#campaign_not_activated?(user_id, campaign_key, api_name) ⇒ Boolean
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/vwo/core/variation_decider.rb', line 202 def campaign_not_activated?(user_id, campaign_key, api_name) if ([ApiMethods::TRACK, ApiMethods::GET_VARIATION_NAME, ApiMethods::GET_FEATURE_VARIABLE_VALUE].include? api_name) && @user_storage_service @logger.log( LogLevelEnum::WARNING, 'CAMPAIGN_NOT_ACTIVATED', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id, '{api}' => api_name } ) @logger.log( LogLevelEnum::INFO, 'CAMPAIGN_NOT_ACTIVATED', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id, '{reason}' => api_name == ApiMethods::TRACK ? 'track it' : 'get the decision/value' } ) return true end false end |
#get_variation(user_id, campaign, api_name, campaign_key, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') ⇒ Object
Returns variation for the user for the passed campaign-key Check if Whitelisting is applicable, evaluate it, if any eligible variation is found,return, otherwise skip it Check in User Storage, if user found, validate variation and return Otherwise, proceed with variation assignment logic
@param :user_id The unique ID assigned to User @param :campaign Campaign hash itself @param :campaign_key The unique ID of the campaign passed @param :goal_identifier The unique campaign’s goal identifier @return (variation_name|Nil): Tuple of
variation_id and variation_name if variation allotted, else nil
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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/vwo/core/variation_decider.rb', line 64 def get_variation(user_id, campaign, api_name, campaign_key, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') campaign_key ||= campaign['key'] return unless campaign is_campaign_part_of_group = @settings_file && part_of_group?(@settings_file, campaign['id']) @has_stored_variation = false decision = initialize_decision_properties(user_id, campaign, api_name, custom_variables, variation_targeting_variables, goal_identifier) decision[:campaign_name] = campaign['name'] if campaign.key?('name') if is_campaign_part_of_group group_id = @settings_file['campaignGroups'][campaign['id'].to_s] decision[:group_id] = group_id group_name = @settings_file['groups'][group_id.to_s]['name'] decision[:group_name] = group_name end # evaluate whitelisting variation = get_variation_if_whitelisting_passed(user_id, campaign, variation_targeting_variables, api_name, decision, true) return variation if variation && variation['name'] if campaign.key?('isAlwaysCheckSegment') is_presegmentation = presegmentation?(campaign, user_id, custom_variables, api_name) return get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision) else user_campaign_map = get_user_storage(user_id, campaign_key) variation = get_stored_variation(user_id, campaign_key, user_campaign_map) if valid_hash?(user_campaign_map) variation = variation.dup if variation # deep copy if variation variation['goal_identifier'] = user_campaign_map['goal_identifier'] if valid_string?(user_campaign_map['goal_identifier']) && api_name == ApiMethods::TRACK @has_stored_variation = true @logger.log( LogLevelEnum::INFO, 'GOT_STORED_VARIATION', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id, '{variationName}' => variation['name'] } ) decision[:from_user_storage_service] = !!variation['name'] decision = add_variation_to_decision_properties(decision, campaign, variation) @hooks_manager.execute(decision) return variation else @logger.log( LogLevelEnum::DEBUG, 'USER_STORAGE_SERVICE_NO_STORED_DATA', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id } ) return if campaign_not_activated?(user_id, campaign_key, api_name) end end # Pre-segmentation is_presegmentation = presegmentation?(campaign, user_id, custom_variables, api_name) is_presegmentation_and_traffic_passed = is_presegmentation && @bucketer.user_part_of_campaign?(user_id, campaign) return nil unless is_presegmentation_and_traffic_passed if is_presegmentation_and_traffic_passed && is_campaign_part_of_group group_campaigns = get_group_campaigns(@settings_file, group_id) if group_campaigns if whitelisting_or_storage_for_grouped_campaigns?(user_id, campaign, group_campaigns, group_name, variation_targeting_variables, true) @logger.log( LogLevelEnum::INFO, 'MEG_CALLED_CAMPAIGN_NOT_WINNER', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id, '{groupName}' => group_name } ) return nil end eligible_campaigns = get_eligible_campaigns(user_id, group_campaigns, campaign, custom_variables) non_eligible_campaigns_key = get_non_eligible_campaigns_key(eligible_campaigns, group_campaigns) @logger.log( LogLevelEnum::DEBUG, 'MEG_ELIGIBLE_CAMPAIGNS', { '{file}' => FILE, '{userId}' => user_id, '{eligibleCampaignKeys}' => get_eligible_campaigns_key(eligible_campaigns).join(','), '{inEligibleText}' => non_eligible_campaigns_key ? "campaigns: + #{non_eligible_campaigns_key.join("'")}" : 'no campaigns', '{groupName}' => group_name } ) @logger.log( LogLevelEnum::INFO, 'MEG_ELIGIBLE_CAMPAIGNS', { '{file}' => FILE, '{userId}' => user_id, '{noOfEligibleCampaigns}' => eligible_campaigns.length, '{noOfGroupCampaigns}' => group_campaigns.length, '{groupName}' => group_name } ) winner_campaign = get_winner_campaign(user_id, eligible_campaigns, group_id) @logger.log( LogLevelEnum::INFO, 'MEG_GOT_WINNER_CAMPAIGN', { '{file}' => FILE, '{userId}' => user_id, '{campaignKey}' => winner_campaign['key'], '{groupName}' => group_name } ) return if meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign) variation = get_variation_allotted(user_id, campaign, true) return nil unless variation && variation['name'] save_user_storage(user_id, campaign_key, campaign['type'], variation['name'], goal_identifier, true) if variation['name'] end end variation ||= get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision) return unless variation variation end |
#get_variation_allotted(user_id, campaign, disable_logs = false) ⇒ Object
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/vwo/core/variation_decider.rb', line 340 def get_variation_allotted(user_id, campaign, disable_logs = false) unless valid_value?(user_id) @logger.log( LogLevelEnum::ERROR, 'USER_ID_INVALID', { '{file}' => FILE, '{userId}' => user_id }, disable_logs ) return end if @bucketer.user_part_of_campaign?(user_id, campaign, true) get_variation_of_campaign_for_user(user_id, campaign, disable_logs) else # not part of campaign @logger.log( LogLevelEnum::INFO, 'USER_NOT_PART_OF_CAMPAIGN', { '{file}' => FILE, '{campaignKey}' => nil, '{userId}' => user_id }, disable_logs ) nil end end |
#get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision) ⇒ Object
Get variation by murmur logic if pre segmentation pass
@param :is_presegmentation The unique key assigned to User @param :campaign Campaign hash for Unique campaign key @param :user_id the unique ID assigned to User @param :goal_identifier goal Identifier used in track API @param :decision data containing campaign info passed to hooks manager
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/vwo/core/variation_decider.rb', line 307 def get_variation_if_presegmentation_applied(is_presegmentation, campaign, user_id, goal_identifier, decision) return nil unless is_presegmentation campaign_key = campaign['key'] variation = get_variation_allotted(user_id, campaign) if variation && variation['name'] save_user_storage(user_id, campaign_key, campaign['type'], variation['name'], goal_identifier) if variation['name'] else @logger.log( LogLevelEnum::INFO, 'DECISION_NO_VARIATION_ALLOTED', { '{file}' => FILE, '{campaignKey}' => campaign_key, '{userId}' => user_id } ) end if variation decision = add_variation_to_decision_properties(decision, campaign, variation) @hooks_manager.execute(decision) end variation end |
#get_variation_of_campaign_for_user(user_id, campaign, disable_logs = false) ⇒ Object
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/vwo/core/variation_decider.rb', line 379 def get_variation_of_campaign_for_user(user_id, campaign, disable_logs = false) variation = @bucketer.bucket_user_to_variation(user_id, campaign, disable_logs) if variation && variation['name'] @logger.log( LogLevelEnum::INFO, 'USER_VARIATION_ALLOCATION_STATUS', { '{file}' => FILE, '{status}' => variation ? "got variation: + #{variation['name']}" : 'did not get any variation', '{userId}' => user_id, '{campaignKey}' => campaign['key'] }, disable_logs ) return variation end if campaign @logger.log( LogLevelEnum::INFO, 'DECISION_NO_VARIATION_ALLOTED', { '{file}' => FILE, '{userId}' => user_id, '{campaignKey}' => campaign['key'] }, disable_logs ) end nil end |
#initialize_decision_properties(user_id, campaign, api_name, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') ⇒ Object
Intitialize decision properties for hook manager
@param :user_id The unique ID assigned to User @param :campaign Campaign hash itself @param :api_name Name of the current api call @param :goal_identifier The unique campaign’s goal identifier @param :custom_variables Key/value pair for segmentation @param :variation_targeting_variables Key/value pair for whitelisting @return Decision properties for the callback by hook manager
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/vwo/core/variation_decider.rb', line 256 def initialize_decision_properties(user_id, campaign, api_name, custom_variables = {}, variation_targeting_variables = {}, goal_identifier = '') { campaign_id: campaign['id'], campaign_key: campaign['key'], campaign_type: campaign['type'], # campaign segmentation conditions custom_variables: custom_variables, # event name event: Hooks::DECISION_TYPES['CAMPAIGN_DECISION'], # goal tracked in case of track API goal_identifier: goal_identifier, # campaign whitelisting flag is_forced_variation_enabled: campaign['isForcedVariationEnabled'] || false, sdk_version: SDK_VERSION, # API name which triggered the event source: api_name, # Passed in API user_id: user_id, # Campaign Whitelisting conditions variation_targeting_variables: variation_targeting_variables, is_user_whitelisted: false, from_user_storage_service: false, # VWO generated UUID based on passed UserId and Account ID vwo_user_id: generator_for(user_id, @settings_file['accountId']) } end |
#meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign) ⇒ Boolean
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/vwo/core/variation_decider.rb', line 230 def meg_called_campaign_not_winner?(user_id, group_name, campaign, winner_campaign) unless winner_campaign && winner_campaign['id'] == campaign['id'] @logger.log( LogLevelEnum::INFO, 'MEG_CALLED_CAMPAIGN_NOT_WINNER', { '{file}' => FILE, '{campaignKey}' => campaign['key'], '{userId}' => user_id, '{groupName}' => group_name } ) return true end false end |
#save_user_storage(user_id, campaign_key, _campaign_type, variation_name, goal_identifier, disable_logs = false) ⇒ Object
If UserStorageService is provided, save the assigned variation
@param :user_id Unique user identifier @param :campaign_key Unique campaign identifier @param :variation_name Variation identifier @param :goal_identifier The unique campaign’s goal identifier @param :disable_logs optional: disable logs if True @return true if found otherwise false
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/vwo/core/variation_decider.rb', line 421 def save_user_storage(user_id, campaign_key, _campaign_type, variation_name, goal_identifier, disable_logs = false) unless @user_storage_service @logger.log( LogLevelEnum::DEBUG, 'USER_STORAGE_SERVICE_NOT_CONFIGURED', { '{file}' => FILE }, disable_logs ) return false end new_campaign_user_mapping = {} new_campaign_user_mapping['campaign_key'] = campaign_key new_campaign_user_mapping['user_id'] = user_id new_campaign_user_mapping['variation_name'] = variation_name new_campaign_user_mapping['goal_identifier'] = goal_identifier unless goal_identifier.empty? @user_storage_service.set(new_campaign_user_mapping) @logger.log( LogLevelEnum::INFO, 'SETTING_DATA_USER_STORAGE_SERVICE', { '{file}' => FILE, '{userId}' => user_id, '{campaignKey}' => campaign_key }, disable_logs ) true rescue StandardError => e @logger.log( LogLevelEnum::ERROR, 'USER_STORAGE_SERVICE_SET_FAILED', { '{file}' => FILE, '{userId}' => user_id, '{error}' => e. }, disable_logs ) false end |
#update_goal_identifier(user_id, campaign, variation, goal_identifier) ⇒ Object
464 465 466 467 468 |
# File 'lib/vwo/core/variation_decider.rb', line 464 def update_goal_identifier(user_id, campaign, variation, goal_identifier) updated_goal_identifier = variation['goal_identifier'] updated_goal_identifier += VWO_DELIMITER + goal_identifier save_user_storage(user_id, campaign['key'], campaign['name'], variation['name'], updated_goal_identifier) if variation['name'] end |