Class: Labkit::RateLimit::Limiter
- Inherits:
-
Object
- Object
- Labkit::RateLimit::Limiter
- 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.
Constant Summary collapse
- NAME_PATTERN =
/\A[a-z0-9_]+\z/
Instance Method Summary collapse
- #check(identifier, cost: 1, rule_context: nil) ⇒ Result
-
#clear(identifier) ⇒ Integer
Discards this limiter's state for one identifier: every rule's counter, and any ban written by a rule carrying ban_for.
-
#initialize(name:, rules:, redis: nil, logger: nil) ⇒ Limiter
constructor
A new instance of Limiter.
-
#peek(identifier, rule_context: nil) ⇒ Result
Read the current rate-limit state without incrementing the counter.
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 |
# 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) @name = validate_name!(name) @evaluator = Evaluator.new( name: @name, rules: prepare_rules(rules), redis: redis || RateLimit.config.redis, logger: @logger ) end |
Instance Method Details
#check(identifier, cost: 1, rule_context: nil) ⇒ Result
47 48 49 50 |
# File 'lib/labkit/rate_limit/limiter.rb', line 47 def check(identifier, cost: 1, rule_context: nil) id = to_identifier(identifier) @evaluator.check(id, cost: cost, rule_context: rule_context) end |
#clear(identifier) ⇒ Integer
Discards this limiter's state for one identifier: every rule's counter, and any ban written by a rule carrying ban_for.
For call sites where a later success should wipe earlier failures, such as an authentication ban cleared by a valid login. Counters otherwise only expire with their window; this is the only way to end one early.
Scoped to this limiter and identifier, not to a single rule: a caller clearing after a success knows who succeeded, not which rules matched.
85 86 87 |
# File 'lib/labkit/rate_limit/limiter.rb', line 85 def clear(identifier) @evaluator.clear(to_identifier(identifier)) end |
#peek(identifier, rule_context: nil) ⇒ Result
Read the current rate-limit state without incrementing the counter. Mirrors #check except the underlying counter is not mutated and the TTL is not extended. Useful for "have we already throttled this caller?" checks where the caller has another path that does the actual increment (typical pattern: peek to gate a side-effect, then call #check on the path that should count).
When the underlying Redis key does not exist yet, the result reports count=0, exceeded=false, and remaining=resolved_limit; matched? is still true because the rule applied. On Redis error the result fails open identically to #check.
67 68 69 70 |
# File 'lib/labkit/rate_limit/limiter.rb', line 67 def peek(identifier, rule_context: nil) id = to_identifier(identifier) @evaluator.peek(id, rule_context: rule_context) end |