class Prop::IntervalStrategy

Public Class Methods

build(options) click to toggle source

Builds the expiring cache key

# File lib/prop/interval_strategy.rb, line 41
def build(options)
  key       = options.fetch(:key)
  handle    = options.fetch(:handle)
  interval  = options.fetch(:interval)

  window    = (Time.now.to_i / interval)
  cache_key = Prop::Key.normalize([ handle, key, window ])

  "prop/v2/#{Digest::MD5.hexdigest(cache_key)}"
end
compare_threshold?(counter, operator, options) click to toggle source
# File lib/prop/interval_strategy.rb, line 31
def compare_threshold?(counter, operator, options)
  return false unless counter
  counter.send operator, options.fetch(:threshold)
end
counter(cache_key, options) click to toggle source
# File lib/prop/interval_strategy.rb, line 12
def counter(cache_key, options)
  cache.read(cache_key).to_i
end
decrement(cache_key, amount, options = {}) click to toggle source
# File lib/prop/interval_strategy.rb, line 22
def decrement(cache_key, amount, options = {})
  raise ArgumentError, "Change amount must be a Integer, was #{amount.class}" unless amount.is_a?(Integer)
  cache.decrement(cache_key, amount, expires_in: options.fetch(:interval, nil)) || (cache.write(cache_key, 0, raw: true, expires_in: options.fetch(:interval, nil)) && 0) # WARNING: potential race condition
end
first_throttled?(counter, options) click to toggle source
# File lib/prop/interval_strategy.rb, line 36
def first_throttled?(counter, options)
  (counter - options.fetch(:increment, 1)) <= options.fetch(:threshold)
end
increment(cache_key, amount, options = {}) click to toggle source

options argument is kept for api consistency for all strategies

# File lib/prop/interval_strategy.rb, line 17
def increment(cache_key, amount, options = {})
  raise ArgumentError, "Change amount must be a Integer, was #{amount.class}" unless amount.is_a?(Integer)
  cache.increment(cache_key, amount, expires_in: options.fetch(:interval, nil)) || (cache.write(cache_key, amount, raw: true, expires_in: options.fetch(:interval, nil)) && amount) # WARNING: potential race condition
end
reset(cache_key, options = {}) click to toggle source
# File lib/prop/interval_strategy.rb, line 27
def reset(cache_key, options = {})
  cache.write(cache_key, zero_counter, raw: true, expires_in: options.fetch(:interval, nil))
end
threshold_reached(options) click to toggle source
# File lib/prop/interval_strategy.rb, line 52
def threshold_reached(options)
  threshold = options.fetch(:threshold)

  "#{options[:handle]} threshold of #{threshold} tries per #{options[:interval]}s exceeded for key #{options[:key].inspect}, hash #{options[:cache_key]}"
end
validate_options!(options) click to toggle source
# File lib/prop/interval_strategy.rb, line 58
def validate_options!(options)
  validate_threshold(options[:threshold], :threshold)
  validate_interval(options[:interval], :interval)

  amount = options[:increment] || options[:decrement]
  if amount
    raise ArgumentError.new(":increment or :decrement must be zero or a positive Integer") if !amount.is_a?(Integer) || amount < 0
  end
end
zero_counter() click to toggle source
# File lib/prop/interval_strategy.rb, line 8
def zero_counter
  0
end

Private Class Methods

cache() click to toggle source
# File lib/prop/interval_strategy.rb, line 78
def cache
  Prop::Limiter.cache
end
validate_interval(option, key) click to toggle source
# File lib/prop/interval_strategy.rb, line 74
def validate_interval(option, key)
  raise ArgumentError.new("#{key.inspect} must be a positive Integer") if !option.is_a?(Integer) || option <= 0
end
validate_threshold(option, key) click to toggle source
# File lib/prop/interval_strategy.rb, line 70
def validate_threshold(option, key)
  raise ArgumentError.new("#{key.inspect} must be a non-negative Integer") if !option.is_a?(Integer) || option < 0
end