1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
-- Time is in milliseconds in this script: TTL, expiry...
local limit = tonumber(ARGV[1])
local expiry = tonumber(ARGV[2]) * 1000
local amount = tonumber(ARGV[3])
if amount > limit then
return false
end
local current_ttl = tonumber(redis.call('pttl', KEYS[2]))
if current_ttl > 0 and current_ttl < expiry then
-- Current window expired, shift it to the previous window
redis.call('rename', KEYS[2], KEYS[1])
redis.call('set', KEYS[2], 0, 'PX', current_ttl + expiry)
end
local previous_count = tonumber(redis.call('get', KEYS[1])) or 0
local previous_ttl = tonumber(redis.call('pttl', KEYS[1])) or 0
local current_count = tonumber(redis.call('get', KEYS[2])) or 0
current_ttl = tonumber(redis.call('pttl', KEYS[2])) or 0
-- If the values don't exist yet, consider the TTL is 0
if previous_ttl <= 0 then
previous_ttl = 0
end
if current_ttl <= 0 then
current_ttl = 0
end
local weighted_count = math.floor(previous_count * previous_ttl / expiry) + current_count
if (weighted_count + amount) > limit then
return false
end
-- If the current counter exists, increase its value
if redis.call('exists', KEYS[2]) == 1 then
redis.call('incrby', KEYS[2], amount)
else
-- Otherwise, set the value with twice the expiry time
redis.call('set', KEYS[2], amount, 'PX', expiry * 2)
end
return true
|