Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /app/experiments
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'app/experiments')
-rw-r--r--app/experiments/application_experiment.rb106
-rw-r--r--app/experiments/members/invite_email_experiment.rb8
2 files changed, 19 insertions, 95 deletions
diff --git a/app/experiments/application_experiment.rb b/app/experiments/application_experiment.rb
index 317514d088b..ed0d146af8c 100644
--- a/app/experiments/application_experiment.rb
+++ b/app/experiments/application_experiment.rb
@@ -3,19 +3,28 @@
class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/NamespacedClass
def enabled?
return false if Feature::Definition.get(feature_flag_name).nil? # there has to be a feature flag yaml file
- return false unless Gitlab.dev_env_or_com? # we're in an environment that allows experiments
+ return false unless Gitlab.dev_env_or_com? # we have to be in an environment that allows experiments
+ # the feature flag has to be rolled out
Feature.get(feature_flag_name).state != :off # rubocop:disable Gitlab/AvoidFeatureGet
end
- def publish(_result)
+ def publish(_result = nil)
+ return unless should_track? # don't track events for excluded contexts
+
track(:assignment) # track that we've assigned a variant for this context
- Gon.global.push({ experiment: { name => signature } }, true) # push to client
+
+ begin
+ Gon.push({ experiment: { name => signature } }, true) # push the experiment data to the client
+ rescue NoMethodError
+ # means we're not in the request cycle, and can't add to Gon. Log a warning maybe?
+ end
end
def track(action, **event_args)
- return unless should_track? # no events for opted out actors or excluded subjects
+ return unless should_track? # don't track events for excluded contexts
+ # track the event, and mix in the experiment signature data
Gitlab::Tracking.event(name, action.to_s, **event_args.merge(
context: (event_args[:context] || []) << SnowplowTracker::SelfDescribingJson.new(
'iglu:com.gitlab/gitlab_experiment/jsonschema/0-3-0', signature
@@ -23,16 +32,8 @@ class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/Namesp
))
end
- def rollout_strategy
- # no-op override in inherited class as desired
- end
-
- def variants
- # override as desired in inherited class with all variants + control
- # %i[variant1 variant2 control]
- #
- # this will make sure we supply variants as these go together - rollout_strategy of :round_robin must have variants
- raise NotImplementedError, "Inheriting class must supply variants as an array if :round_robin strategy is used" if rollout_strategy == :round_robin
+ def exclude!
+ @excluded = true
end
private
@@ -41,80 +42,7 @@ class ApplicationExperiment < Gitlab::Experiment # rubocop:disable Gitlab/Namesp
name.tr('/', '_')
end
- def resolve_variant_name
- case rollout_strategy
- when :round_robin
- round_robin_rollout
- else
- percentage_rollout
- end
- end
-
- def round_robin_rollout
- Strategy::RoundRobin.new(feature_flag_name, variants).execute
- end
-
- def percentage_rollout
- return variant_names.first if Feature.enabled?(feature_flag_name, self, type: :experiment, default_enabled: :yaml)
-
- nil # Returning nil vs. :control is important for not caching and rollouts.
- end
-
- # Cache is an implementation on top of Gitlab::Redis::SharedState that also
- # adheres to the ActiveSupport::Cache::Store interface and uses the redis
- # hash data type.
- #
- # Since Gitlab::Experiment can use any type of caching layer, utilizing the
- # long lived shared state interface here gives us an efficient way to store
- # context keys and the variant they've been assigned -- while also giving us
- # a simple way to clean up an experiments data upon resolution.
- #
- # The data structure:
- # key: experiment.name
- # fields: context key => variant name
- #
- # The keys are expected to be `experiment_name:context_key`, which is the
- # default cache key strategy. So running `cache.fetch("foo:bar", "value")`
- # would create/update a hash with the key of "foo", with a field named
- # "bar" that has "value" assigned to it.
- class Cache < ActiveSupport::Cache::Store # rubocop:disable Gitlab/NamespacedClass
- # Clears the entire cache for a given experiment. Be careful with this
- # since it would reset all resolved variants for the entire experiment.
- def clear(key:)
- key = hkey(key)[0] # extract only the first part of the key
- pool do |redis|
- case redis.type(key)
- when 'hash', 'none' then redis.del(key)
- else raise ArgumentError, 'invalid call to clear a non-hash cache key'
- end
- end
- end
-
- private
-
- def pool
- raise ArgumentError, 'missing block' unless block_given?
-
- Gitlab::Redis::SharedState.with { |redis| yield redis }
- end
-
- def hkey(key)
- key.to_s.split(':') # this assumes the default strategy in gitlab-experiment
- end
-
- def read_entry(key, **options)
- value = pool { |redis| redis.hget(*hkey(key)) }
- value.nil? ? nil : ActiveSupport::Cache::Entry.new(value)
- end
-
- def write_entry(key, entry, **options)
- return false if entry.value.blank? # don't cache any empty values
-
- pool { |redis| redis.hset(*hkey(key), entry.value) }
- end
-
- def delete_entry(key, **options)
- pool { |redis| redis.hdel(*hkey(key)) }
- end
+ def experiment_group?
+ Feature.enabled?(feature_flag_name, self, type: :experiment, default_enabled: :yaml)
end
end
diff --git a/app/experiments/members/invite_email_experiment.rb b/app/experiments/members/invite_email_experiment.rb
index 4a03ebb7726..a0f4dee2866 100644
--- a/app/experiments/members/invite_email_experiment.rb
+++ b/app/experiments/members/invite_email_experiment.rb
@@ -7,12 +7,8 @@ module Members
INVITE_TYPE = 'initial_email'
- def rollout_strategy
- :round_robin
- end
-
- def variants
- %i[avatar permission_info control]
+ def resolve_variant_name
+ Strategy::RoundRobin.new(feature_flag_name, %i[avatar permission_info control]).execute
end
end
end