Class: Berater::RateLimiter
- Defined in:
- lib/berater/rate_limiter.rb
Constant Summary collapse
- LUA_SCRIPT =
Berater::LuaScript("local key = KEYS[1]\nlocal ts = tonumber(ARGV[1])\nlocal capacity = tonumber(ARGV[2])\nlocal interval_msec = tonumber(ARGV[3])\nlocal cost = tonumber(ARGV[4])\n\nlocal allowed -- whether lock was acquired\nlocal count -- capacity being utilized\nlocal msec_per_drip = interval_msec / capacity\nlocal state = redis.call('GET', key)\n\nif state then\n local last_ts -- timestamp of last update\n count, last_ts = string.match(state, '([%d.]+);(%w+)')\n count = tonumber(count)\n last_ts = tonumber(last_ts, 16)\n\n -- adjust for time passing, guarding against clock skew\n if ts > last_ts then\n local drips = math.floor((ts - last_ts) / msec_per_drip)\n count = math.max(0, count - drips)\n else\n ts = last_ts\n end\nelse\n count = 0\nend\n\nif cost == 0 then\n -- just checking count\n allowed = true\nelse\n allowed = (count + cost) <= capacity\n\n if allowed then\n count = count + cost\n\n -- time for bucket to empty, in milliseconds\n local ttl = math.ceil(count * msec_per_drip)\n ttl = ttl + 100 -- margin of error, for clock skew\n\n -- update count and last_ts, with expiration\n state = string.format('%f;%X', count, ts)\n redis.call('SET', key, state, 'PX', ttl)\n end\nend\n\nreturn { tostring(count), allowed }\n" )
Constants inherited from Limiter
Instance Attribute Summary
Attributes inherited from Limiter
Instance Method Summary collapse
-
#initialize(key, capacity, interval, **opts) ⇒ RateLimiter
constructor
A new instance of RateLimiter.
- #interval ⇒ Object
- #to_s ⇒ Object
Methods inherited from Limiter
#==, cache_key, #limit, new, #redis, #utilization
Constructor Details
#initialize(key, capacity, interval, **opts) ⇒ RateLimiter
Returns a new instance of RateLimiter.
4 5 6 7 |
# File 'lib/berater/rate_limiter.rb', line 4 def initialize(key, capacity, interval, **opts) super(key, capacity, interval, **opts) self.interval = interval end |
Instance Method Details
#interval ⇒ Object
9 10 11 |
# File 'lib/berater/rate_limiter.rb', line 9 def interval args[0] end |
#to_s ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/berater/rate_limiter.rb', line 90 def to_s msg = if interval.is_a? Numeric if interval == 1 "every second" else "every #{interval} seconds" end else "per #{interval}" end "#<#{self.class}(#{key}: #{capacity} #{msg})>" end |