Class: SimpleHttpService::RateLimiter
- Inherits:
-
Object
- Object
- SimpleHttpService::RateLimiter
- Defined in:
- lib/simple_http_service/rate_limiter.rb
Overview
Sliding-window rate limiter, shared per key across all Client instances in the process. Thread safe.
Constant Summary collapse
- DEFAULT_INTERVAL =
60
Instance Attribute Summary collapse
-
#interval ⇒ Object
readonly
Returns the value of attribute interval.
-
#limit ⇒ Object
readonly
Returns the value of attribute limit.
Class Method Summary collapse
-
.for(key, limit:, interval: DEFAULT_INTERVAL) ⇒ Object
Returns the limiter registered for
key, creating it on first use. -
.reset! ⇒ Object
Drops every registered limiter.
Instance Method Summary collapse
-
#acquire(wait: false) ⇒ Object
Consumes one slot.
-
#initialize(limit:, interval: DEFAULT_INTERVAL) ⇒ RateLimiter
constructor
A new instance of RateLimiter.
-
#remaining ⇒ Object
Slots still available in the current window.
Constructor Details
#initialize(limit:, interval: DEFAULT_INTERVAL) ⇒ RateLimiter
Returns a new instance of RateLimiter.
46 47 48 49 50 51 52 53 54 |
# File 'lib/simple_http_service/rate_limiter.rb', line 46 def initialize(limit:, interval: DEFAULT_INTERVAL) raise 'rate limit must be a positive integer' unless limit.to_i.positive? raise 'rate limit interval must be positive' unless interval.to_f.positive? @limit = limit.to_i @interval = interval.to_f @timestamps = [] @mutex = Mutex.new end |
Instance Attribute Details
#interval ⇒ Object (readonly)
Returns the value of attribute interval.
20 21 22 |
# File 'lib/simple_http_service/rate_limiter.rb', line 20 def interval @interval end |
#limit ⇒ Object (readonly)
Returns the value of attribute limit.
20 21 22 |
# File 'lib/simple_http_service/rate_limiter.rb', line 20 def limit @limit end |
Class Method Details
.for(key, limit:, interval: DEFAULT_INTERVAL) ⇒ Object
Returns the limiter registered for key, creating it on first use.
24 25 26 27 28 |
# File 'lib/simple_http_service/rate_limiter.rb', line 24 def for(key, limit:, interval: DEFAULT_INTERVAL) registry_mutex.synchronize do registry[key] ||= new(limit: limit, interval: interval) end end |
.reset! ⇒ Object
Drops every registered limiter. Mainly useful in tests.
31 32 33 |
# File 'lib/simple_http_service/rate_limiter.rb', line 31 def reset! registry_mutex.synchronize { registry.clear } end |
Instance Method Details
#acquire(wait: false) ⇒ Object
Consumes one slot. Raises RateLimitExceeded when the window is full,
unless wait is true, in which case it sleeps until a slot frees up.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/simple_http_service/rate_limiter.rb', line 58 def acquire(wait: false) loop do retry_after = try_acquire return true unless retry_after unless wait raise RateLimitExceeded.new( "rate limit of #{limit} request(s) per #{interval.round} seconds exceeded, " \ "retry in #{retry_after.ceil} second(s)", retry_after: retry_after ) end sleep(retry_after) end end |
#remaining ⇒ Object
Slots still available in the current window.
76 77 78 79 80 81 |
# File 'lib/simple_http_service/rate_limiter.rb', line 76 def remaining @mutex.synchronize do prune limit - @timestamps.size end end |