Class: Prop::IntervalStrategy

Inherits:
Object
  • Object
show all
Defined in:
lib/prop/interval_strategy.rb

Class Method Summary collapse

Class Method Details

.build(options) ⇒ Object

Builds the expiring cache key



41
42
43
44
45
46
47
48
49
50
# 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) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
# 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) ⇒ Object



12
13
14
# 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 = {}) ⇒ Object

Raises:

  • (ArgumentError)


22
23
24
25
# 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) || (cache.write(cache_key, 0, raw: true) && 0) # WARNING: potential race condition
end

.first_throttled?(counter, options) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
# 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 = {}) ⇒ Object

options argument is kept for api consistency for all strategies

Raises:

  • (ArgumentError)


17
18
19
20
# 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) || (cache.write(cache_key, amount, raw: true) && amount) # WARNING: potential race condition
end

.reset(cache_key) ⇒ Object



27
28
29
# File 'lib/prop/interval_strategy.rb', line 27

def reset(cache_key)
  cache.write(cache_key, zero_counter, raw: true)
end

.threshold_reached(options) ⇒ Object



52
53
54
55
56
# 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) ⇒ Object



58
59
60
61
62
63
64
65
66
# File 'lib/prop/interval_strategy.rb', line 58

def validate_options!(options)
  validate_positive_integer(options[:threshold], :threshold)
  validate_positive_integer(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_counterObject



8
9
10
# File 'lib/prop/interval_strategy.rb', line 8

def zero_counter
  0
end