Class: Philiprehberger::RateLimiter::SlidingWindow
- Inherits:
-
Object
- Object
- Philiprehberger::RateLimiter::SlidingWindow
- Includes:
- StatsTracking
- Defined in:
- lib/philiprehberger/rate_limiter/sliding_window.rb
Instance Attribute Summary collapse
-
#limit ⇒ Object
readonly
Returns the value of attribute limit.
-
#window ⇒ Object
readonly
Returns the value of attribute window.
Instance Method Summary collapse
- #allow?(key, weight: 1) ⇒ Boolean
-
#allow_batch(keys) ⇒ Hash{Object => Boolean}
Check many keys in a single mutex acquisition.
-
#clear ⇒ void
Clear state for all keys (resets quotas and stats for every tracked key).
-
#drain(key = :default) ⇒ Integer
Forcefully consume all remaining capacity for a key.
- #info(key) ⇒ Object
-
#initialize(limit:, window:) ⇒ SlidingWindow
constructor
A new instance of SlidingWindow.
- #peek(key) ⇒ Object
- #refund(key, amount: 1) ⇒ Object
- #remaining(key) ⇒ Object
- #reset(key) ⇒ Object
-
#retry_after(key = :default) ⇒ Float
Seconds until the next request would be allowed, suitable for the HTTP Retry-After header.
-
#used(key) ⇒ Integer
Number of currently consumed slots for a key (after expiring old entries).
-
#wait_time(key = :default) ⇒ Float
Seconds until the next request would be allowed.
-
#window_reset_at(key = :default) ⇒ Time?
Time when the current window expires.
Methods included from StatsTracking
#allow!, #keys, #on_reject, #stats, #throttle
Constructor Details
#initialize(limit:, window:) ⇒ SlidingWindow
Returns a new instance of SlidingWindow.
12 13 14 15 16 17 18 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 12 def initialize(limit:, window:) @limit = limit @window = window @store = {} @mutex = Mutex.new init_stats end |
Instance Attribute Details
#limit ⇒ Object (readonly)
Returns the value of attribute limit.
10 11 12 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 10 def limit @limit end |
#window ⇒ Object (readonly)
Returns the value of attribute window.
10 11 12 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 10 def window @window end |
Instance Method Details
#allow?(key, weight: 1) ⇒ Boolean
20 21 22 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 20 def allow?(key, weight: 1) @mutex.synchronize { try_acquire(key, weight) } end |
#allow_batch(keys) ⇒ Hash{Object => Boolean}
Check many keys in a single mutex acquisition.
28 29 30 31 32 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 28 def allow_batch(keys) @mutex.synchronize do keys.to_h { |key| [key, try_acquire(key, 1)] } end end |
#clear ⇒ void
This method returns an undefined value.
Clear state for all keys (resets quotas and stats for every tracked key)
60 61 62 63 64 65 66 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 60 def clear @mutex.synchronize do @store.clear @stats_store.clear end nil end |
#drain(key = :default) ⇒ Integer
Forcefully consume all remaining capacity for a key.
80 81 82 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 80 def drain(key = :default) @mutex.synchronize { drain_entries(key) } end |
#info(key) ⇒ Object
68 69 70 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 68 def info(key) @mutex.synchronize { build_info(key) } end |
#peek(key) ⇒ Object
34 35 36 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 34 def peek(key) @mutex.synchronize { count_remaining(key).positive? } end |
#refund(key, amount: 1) ⇒ Object
72 73 74 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 72 def refund(key, amount: 1) @mutex.synchronize { refund_entries(key, amount) } end |
#remaining(key) ⇒ Object
38 39 40 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 38 def remaining(key) @mutex.synchronize { count_remaining(key) } end |
#reset(key) ⇒ Object
53 54 55 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 53 def reset(key) @mutex.synchronize { @store.delete(key.to_s) } end |
#retry_after(key = :default) ⇒ Float
Seconds until the next request would be allowed, suitable for the HTTP Retry-After header. Returns 0.0 when a request is allowed right now.
107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 107 def retry_after(key = :default) @mutex.synchronize do cleanup(key) entries = fetch_entries(key) return 0.0 if entries.length < @limit oldest = entries.min return 0.0 if oldest.nil? wait = (oldest + @window) - now [wait, 0.0].max end end |
#used(key) ⇒ Integer
Number of currently consumed slots for a key (after expiring old entries).
46 47 48 49 50 51 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 46 def used(key) @mutex.synchronize do cleanup(key) fetch_entries(key).length end end |
#wait_time(key = :default) ⇒ Float
Seconds until the next request would be allowed
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 88 def wait_time(key = :default) @mutex.synchronize do cleanup(key) entries = fetch_entries(key) return 0.0 if entries.length < @limit oldest = entries.min return 0.0 if oldest.nil? wait = oldest + @window - now [wait, 0.0].max end end |
#window_reset_at(key = :default) ⇒ Time?
Time when the current window expires
125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/philiprehberger/rate_limiter/sliding_window.rb', line 125 def window_reset_at(key = :default) @mutex.synchronize do entries = fetch_entries(key) return nil if entries.empty? cleanup(key) entries = fetch_entries(key) return nil if entries.empty? oldest = entries.min elapsed = now - oldest Time.now + (@window - elapsed) end end |