Class: ActiveHarness::RateLimit::RequestLimiter
- Inherits:
-
Object
- Object
- ActiveHarness::RateLimit::RequestLimiter
- Defined in:
- lib/active_harness/rate_limit/request_limiter.rb
Overview
Sliding-window rate limiter. Tracks request timestamps per user_id and raises if the limit is exceeded within the rolling time window.
Storage is in-memory (per-process). For multi-process environments, replace with a shared backend (Redis, Memcached, etc.) by subclassing and overriding #timestamps_for / #record_timestamp.
Usage:
limiter = RequestLimiter.new(max_requests: 10, window_seconds: 60)
limiter.check!(user_id) # call before each request; raises if over limit
Constant Summary collapse
- DEFAULT_MAX =
10- DEFAULT_WINDOW =
seconds
60
Instance Method Summary collapse
-
#check!(user_id) ⇒ Object
Records this request and raises if the limit has been reached.
-
#initialize(max_requests: DEFAULT_MAX, window_seconds: DEFAULT_WINDOW) ⇒ RequestLimiter
constructor
A new instance of RequestLimiter.
Constructor Details
#initialize(max_requests: DEFAULT_MAX, window_seconds: DEFAULT_WINDOW) ⇒ RequestLimiter
Returns a new instance of RequestLimiter.
20 21 22 23 24 25 |
# File 'lib/active_harness/rate_limit/request_limiter.rb', line 20 def initialize(max_requests: DEFAULT_MAX, window_seconds: DEFAULT_WINDOW) @max_requests = max_requests @window_seconds = window_seconds @log = Hash.new { |h, k| h[k] = [] } @mutex = Mutex.new end |
Instance Method Details
#check!(user_id) ⇒ Object
Records this request and raises if the limit has been reached.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/active_harness/rate_limit/request_limiter.rb', line 30 def check!(user_id) return if user_id.nil? key = user_id.to_s now = Time.now.to_f cutoff = now - @window_seconds @mutex.synchronize do @log[key].reject! { |t| t < cutoff } if @log[key].size >= @max_requests raise Errors::RequestThrottledError, "Rate limit exceeded: #{@max_requests} requests/#{@window_seconds}s (user: #{key})" end @log[key] << now end end |