Class: NbApiClient::RateLimiter
- Inherits:
-
Object
- Object
- NbApiClient::RateLimiter
- Defined in:
- lib/nb_api_client/rate_limiter.rb
Overview
A global (cross-process, cross-thread) distributed rate limiter backed by configuration.cache_store (the same store used for unauthorized-response tracking; defaults to Rails.cache). Implements a "sliding window counter" algorithm: each window is divided into fixed buckets, and the previous bucket's count is weighted by how much of it still overlaps the sliding window. This approximates a true sliding window without requiring sorted-set support, so it works with any ActiveSupport::Cache::Store (memory, Redis, Memcached, ...). All callers share one window (configure via NbApiClient.configure).
If no cache_store is configured, rate limiting is disabled entirely (every request is allowed through immediately).
Defined Under Namespace
Classes: RateLimitExhausted
Class Method Summary collapse
-
.with_limit(&block) ⇒ Object
Blocks until a request slot is available, then yields to the caller.
Instance Method Summary collapse
-
#initialize ⇒ RateLimiter
constructor
A new instance of RateLimiter.
- #with_limit ⇒ Object
Constructor Details
#initialize ⇒ RateLimiter
Returns a new instance of RateLimiter.
25 26 27 |
# File 'lib/nb_api_client/rate_limiter.rb', line 25 def initialize @key = "nb_rate_limit:window" end |
Class Method Details
.with_limit(&block) ⇒ Object
Blocks until a request slot is available, then yields to the caller. Raises RateLimitExhausted if the wait exceeds configuration.rate_limit_max_wait_seconds.
21 22 23 |
# File 'lib/nb_api_client/rate_limiter.rb', line 21 def self.with_limit(&block) new.with_limit(&block) end |
Instance Method Details
#with_limit ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/nb_api_client/rate_limiter.rb', line 29 def with_limit config = NbApiClient.configuration waited = 0.0 loop do result = try_acquire_slot if result > 0 return yield else if waited >= config.rate_limit_max_wait_seconds raise RateLimitExhausted, "Rate limit exhausted after waiting #{waited}s" end # Sleep with jitter to spread retries and avoid thundering herd sleep_time = config.rate_limit_poll_interval + rand(0.0..config.rate_limit_max_jitter) sleep(sleep_time) waited += sleep_time end end rescue RateLimitExhausted raise rescue StandardError => e # Fail open: if the cache store is unavailable, allow the request through. # NbApiClient::Request's 429 handling acts as a safety net. config.logger&.warn("[NbApiClient::RateLimiter] cache store error, failing open: #{e.class} - #{e.}") yield end |