debian-mirror-gitlab/app/experiments/strategy/round_robin.rb
2021-03-11 19:13:27 +05:30

78 lines
1.6 KiB
Ruby

# frozen_string_literal: true
module Strategy
class RoundRobin
CacheError = Class.new(StandardError)
COUNTER_EXPIRE_TIME = 86400 # one day
def initialize(key, variants)
@key = key
@variants = variants
end
def execute
increment_counter
resolve_variant_name
end
# When the counter would expire
#
# @api private Used internally by SRE and debugging purpose
# @return [Integer] Number in seconds until expiration or false if never
def counter_expires_in
Gitlab::Redis::SharedState.with do |redis|
redis.ttl(key)
end
end
# Return the actual counter value
#
# @return [Integer] value
def counter_value
Gitlab::Redis::SharedState.with do |redis|
(redis.get(key) || 0).to_i
end
end
# Reset the counter
#
# @private Used internally by SRE and debugging purpose
# @return [Boolean] whether reset was a success
def reset!
redis_cmd do |redis|
redis.del(key)
end
end
private
attr_reader :key, :variants
# Increase the counter
#
# @return [Boolean] whether operation was a success
def increment_counter
redis_cmd do |redis|
redis.incr(key)
redis.expire(key, COUNTER_EXPIRE_TIME)
end
end
def resolve_variant_name
remainder = counter_value % variants.size
variants[remainder]
end
def redis_cmd
Gitlab::Redis::SharedState.with { |redis| yield(redis) }
true
rescue CacheError => e
Gitlab::AppLogger.warn("GitLab: An unexpected error occurred in writing to Redis: #{e}")
false
end
end
end