Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 1 addition & 71 deletions lib/optimizely/config/datafile_project_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ class DatafileProjectConfig < ProjectConfig
:group_id_map, :rollout_id_map, :rollout_experiment_id_map, :variation_id_map,
:variation_id_to_variable_usage_map, :variation_key_map, :variation_id_map_by_experiment_id,
:variation_key_map_by_experiment_id, :flag_variation_map, :integration_key_map, :integrations,
:public_key_for_odp, :host_for_odp, :all_segments, :region, :holdouts, :holdout_id_map,
:global_holdouts, :included_holdouts, :excluded_holdouts, :flag_holdouts_map
:public_key_for_odp, :host_for_odp, :all_segments, :region, :holdouts, :holdout_id_map
# Boolean - denotes if Optimizely should remove the last block of visitors' IP address before storing event data
attr_reader :anonymize_ip

Expand Down Expand Up @@ -115,10 +114,6 @@ def initialize(datafile, logger, error_handler)
@variation_id_to_experiment_map = {}
@flag_variation_map = {}
@holdout_id_map = {}
@global_holdouts = []
@included_holdouts = {}
@excluded_holdouts = {}
@flag_holdouts_map = {}

@holdouts.each do |holdout|
next unless holdout['status'] == 'Running'
Expand All @@ -127,31 +122,6 @@ def initialize(datafile, logger, error_handler)
holdout['layerId'] ||= ''

@holdout_id_map[holdout['id']] = holdout

included_flags = holdout['includedFlags'] || []
excluded_flags = holdout['excludedFlags'] || []

case [included_flags.empty?, excluded_flags.empty?]
when [true, true]
# No included or excluded flags - this is a global holdout
@global_holdouts << holdout

when [false, true], [false, false]
# Has included flags - add to included_holdouts map
included_flags.each do |flag_id|
@included_holdouts[flag_id] ||= []
@included_holdouts[flag_id] << holdout
end

when [true, false]
# No included flags but has excluded flags - global with exclusions
@global_holdouts << holdout

excluded_flags.each do |flag_id|
@excluded_holdouts[flag_id] ||= []
@excluded_holdouts[flag_id] << holdout
end
end
end

@experiment_id_map.each_value do |exp|
Expand Down Expand Up @@ -658,46 +628,6 @@ def rollout_experiment?(experiment_id)
@rollout_experiment_id_map.key?(experiment_id)
end

def get_holdouts_for_flag(flag_id)
# Helper method to get holdouts from an applied feature flag
#
# flag_id - (REQUIRED) ID of the feature flag
# This parameter is required and should not be null/nil
#
# Returns the holdouts that apply for a specific flag

return [] if @holdouts.nil? || @holdouts.empty?

# Check cache first (before validation, so we cache the validation result too)
return @flag_holdouts_map[flag_id] if @flag_holdouts_map.key?(flag_id)

# Validate that the flag exists in the datafile
flag_exists = @feature_flags.any? { |flag| flag['id'] == flag_id }
unless flag_exists
# Cache the empty result for non-existent flags
@flag_holdouts_map[flag_id] = []
return []
end

# Prioritize global holdouts first
excluded = @excluded_holdouts[flag_id] || []

active_holdouts = if excluded.any?
@global_holdouts.reject { |holdout| excluded.include?(holdout) }
else
@global_holdouts.dup
end

# Append included holdouts
included = @included_holdouts[flag_id] || []
active_holdouts.concat(included)

# Cache the result
@flag_holdouts_map[flag_id] = active_holdouts

@flag_holdouts_map[flag_id] || []
end

def get_holdout(holdout_id)
# Helper method to get holdout from holdout ID
#
Expand Down
9 changes: 5 additions & 4 deletions lib/optimizely/decision_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,10 @@ def get_variation_for_feature(project_config, feature_flag, user_context, decide
# user_context - Optimizely user context instance
#
# Returns DecisionResult struct.
holdouts = project_config.get_holdouts_for_flag(feature_flag['id'])
# Get running holdouts from the holdout_id_map (all holdouts are global now)
running_holdouts = project_config.holdout_id_map.values

if holdouts && !holdouts.empty?
if running_holdouts && !running_holdouts.empty?
# Has holdouts - use get_decision_for_flag which checks holdouts first
get_decision_for_flag(feature_flag, user_context, project_config, decide_options)
else
Expand All @@ -195,8 +196,8 @@ def get_decision_for_flag(feature_flag, user_context, project_config, decide_opt
reasons = decide_reasons ? decide_reasons.dup : []
user_id = user_context.user_id

# Check holdouts
holdouts = project_config.get_holdouts_for_flag(feature_flag['id'])
# Check holdouts (all holdouts are global now - apply to all flags)
holdouts = project_config.holdout_id_map.values

holdouts.each do |holdout|
holdout_decision = get_variation_for_holdout(holdout, user_context, project_config)
Expand Down
8 changes: 0 additions & 8 deletions lib/optimizely/helpers/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,6 @@ module Constants
},
'status' => {
'type' => 'string'
},
'includedFlags' => {
'type' => 'array',
'items' => {'type' => 'string'}
},
'excludedFlags' => {
'type' => 'array',
'items' => {'type' => 'string'}
}
}
}
Expand Down
Loading
Loading