Class: Startback::Security::RateLimiter

Inherits:
Object
  • Object
show all
Includes:
Startback::Support::Robustness
Defined in:
lib/startback/security/rate_limiter.rb

Overview

This class can be used as operation arounder to skip operation executions via a rate limiting process.

Example:

RATE_LIMITER = Startback::Security::RateLimiter.new({
  store: Startback::Caching::Store.new,  # use a redis cache store in practice
  defaults: {
    strategy: :silent_drop,
    detection: :input,
    periodicity: 60,
    max_occurence: 3,
  },
})

# in api.rb
around_run(RATE_LIMITER)

# in an operation.rb
class Op < Startback::Operation
  rate_limit { max_occurences: 2 }   # Partial<Config>
  rate_limit :dynamic_config         # Config obtained on op instance
end

Reference:

strategy: Symbol => :silent_drop or :fail (429 status code)
detection: Symbol => method to call on Operation instance to detect call duplicates via pure data
periodicity: Integer => periodicity of occurence count, in seconds
max_occurences: Integer => max number of occurences during the period

Constant Summary collapse

DEFAULT_OPTIONS =
{
  max_occurences: 1
}

Instance Method Summary collapse

Methods included from Startback::Support::Robustness

#log, #logger_for, #monitor, #stop_errors, #try_max_times

Constructor Details

#initialize(options = {}) ⇒ RateLimiter

Returns a new instance of RateLimiter.



44
45
46
47
48
# File 'lib/startback/security/rate_limiter.rb', line 44

def initialize(options = {})
  @options = DEFAULT_OPTIONS.merge(options)

  configuration_error!("Missing store") unless @options[:store]
end

Instance Method Details

#call(runner, op, &then_block) ⇒ Object

Raises:

  • (ArgumentError)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/startback/security/rate_limiter.rb', line 50

def call(runner, op, &then_block)
  raise ArgumentError, "A block is required" unless then_block

  if op.class.has_rate_limit?
    limit_options = op.class.rate_limit_options(op, defaults || {})
    key, authorized = authorize_call!(op, limit_options)
    unless authorized
      log_rate_limited(op, key, limit_options)
      return nil
    end
  end

  then_block.call
end