Class: Labkit::RateLimit::Limiter

Inherits:
Object
  • Object
show all
Defined in:
lib/labkit/rate_limit/limiter.rb

Overview

Limiter is the primary public API for rate limiting. Instantiate once per call site (e.g. at application boot), then call #check(identifier) on every request. The internal Evaluator is reused across calls, avoiding per-request object allocation.

Examples:

limiter = Labkit::RateLimit::Limiter.new(
  name: "rack_request",
  rules: [Labkit::RateLimit::Rule.new(name: "api_user", limit: 100, period: 60, characteristics: [:user])]
)
result = limiter.check({ user: 42, ip: "1.2.3.4" })
render_429 if result.exceeded? && result.action == :block

Constant Summary collapse

NAME_PATTERN =
/\A[a-z0-9_]+\z/

Instance Method Summary collapse

Constructor Details

#initialize(name:, rules:, redis: nil, logger: nil) ⇒ Limiter

Returns a new instance of Limiter.



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/labkit/rate_limit/limiter.rb', line 22

def initialize(name:, rules:, redis: nil, logger: nil)
  @logger = logger || RateLimit.config.logger || Labkit::Logging::JsonLogger.new($stdout)
  validated_name = validate_name!(name)
  @name = validated_name

  @evaluator = Evaluator.new(
    name: validated_name,
    rules: prepare_rules(rules),
    redis: redis || RateLimit.config.redis,
    logger: @logger
  )
end

Instance Method Details

#check(identifier) ⇒ Result

Parameters:

  • identifier (Identifier, Hash)

    caller attributes for this request

Returns:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/labkit/rate_limit/limiter.rb', line 37

def check(identifier)
  id = identifier.is_a?(Identifier) ? identifier : Identifier.new(identifier)
  result = @evaluator.check(id)

  if result.exceeded? && result.action == :block
    @logger.warn(
      message: "rate_limit_check",
      name: @name,
      rule_name: result.rule.name,
      exceeded: true,
      severity: "WARN"
    )
  end

  result
end