local key = KEYS[1]
local burst = tonumber(ARGV[1])
local refill_per_sec = tonumber(ARGV[2])
local now_ms = tonumber(ARGV[3])
local data = redis.call('HMGET', key, 'tokens', 'ts')
local tokens = tonumber(data[1])
local last_ts = tonumber(data[2])
if tokens == nil then
tokens = burst
last_ts = now_ms
end
local elapsed_secs = math.max(0, (now_ms - last_ts) / 1000.0)
tokens = math.min(burst, tokens + elapsed_secs * refill_per_sec)
local allowed = 0
local remaining = 0
local retry_after_secs = 0
if tokens >= 1.0 then
tokens = tokens - 1.0
allowed = 1
remaining = math.floor(tokens)
else
allowed = 0
local deficit = 1.0 - tokens
retry_after_secs = math.ceil(deficit / refill_per_sec)
if retry_after_secs < 1 then retry_after_secs = 1 end
if retry_after_secs > 604800 then retry_after_secs = 604800 end
end
local expiry_secs = math.min(math.ceil(burst / refill_per_sec) + 2, 604800)
local stored_ts = math.max(now_ms, last_ts)
redis.call('HSET', key, 'tokens', tostring(tokens), 'ts', tostring(stored_ts))
redis.call('EXPIRE', key, expiry_secs)
return {allowed, remaining, retry_after_secs}