-- key
local key = KEYS[1]
-- 最大儲存的令牌數
local max_permits = tonumber(KEYS[2])
-- 每秒鐘產生的令牌數
local permits_per_second = tonumber(KEYS[3])
-- 請求的令牌數
local required_permits = tonumber(ARGV[1])
-- 下次請求可以獲取令牌的起始時間
local next_free_ticket_micros = tonumber(redis.call('hget', key, 'next_free_ticket_micros') or 0)
-- 當前時間
local time = redis.call('time')
local now_micros = tonumber(time[1]) * 1000000 + tonumber(time[2])
-- 查詢獲取令牌是否超時
if (ARGV[2] ~= nil) then
-- 獲取令牌的超時時間
local timeout_micros = tonumber(ARGV[2])
local micros_to_wait = next_free_ticket_micros - now_micros
if (micros_to_wait > timeout_micros) then
return micros_to_wait
end
end
-- 當前儲存的令牌數
local stored_permits = tonumber(redis.call('hget', key, 'stored_permits') or 0)
-- 新增令牌的時間間隔
local stable_interval_micros = 1000000 / permits_per_second
-- 補充令牌
if (now_micros > next_free_ticket_micros) then
local new_permits = (now_micros - next_free_ticket_micros) / stable_interval_micros
stored_permits = math.min(max_permits, stored_permits + new_permits)
next_free_ticket_micros = now_micros
end
-- 消耗令牌
local moment_available = next_free_ticket_micros
local stored_permits_to_spend = math.min(required_permits, stored_permits)
local fresh_permits = required_permits - stored_permits_to_spend;
local wait_micros = fresh_permits * stable_interval_micros
redis.replicate_commands()
redis.call('hset', key, 'stored_permits', stored_permits - stored_permits_to_spend)
redis.call('hset', key, 'next_free_ticket_micros', next_free_ticket_micros + wait_micros)
redis.call('expire', key, 10)
-- 返回需要等待的時間長度
return moment_available - now_micros