local key = KEYS[1] -- identifier including prefixes local maxTokens = tonumber(ARGV[1]) -- maximum number of tokens local interval = tonumber(ARGV[2]) -- size of the window in milliseconds local refillRate = tonumber(ARGV[3]) -- how many tokens are refilled after each interval local now = tonumber(ARGV[4]) -- current timestamp in milliseconds local incrementBy = tonumber(ARGV[5]) -- how many tokens to consume, default is 1 local bucket = redis.call("HMGET", key, "refilledAt", "tokens") local refilledAt local tokens if bucket[1] == false then refilledAt = now tokens = maxTokens else refilledAt = tonumber(bucket[1]) tokens = tonumber(bucket[2]) end if now >= refilledAt + interval then local numRefills = math.floor((now - refilledAt) / interval) tokens = math.min(maxTokens, tokens + numRefills * refillRate) refilledAt = refilledAt + numRefills * interval end if tokens == 0 then return {-1, refilledAt + interval} end local remaining = tokens - incrementBy local expireAt = math.ceil(((maxTokens - remaining) / refillRate)) * interval redis.call("HSET", key, "refilledAt", refilledAt, "tokens", remaining) redis.call("PEXPIRE", key, expireAt) return {remaining, refilledAt + interval}