Skip to content

Instantly share code, notes, and snippets.

@clbarnes
Last active April 7, 2025 08:52
Show Gist options
  • Save clbarnes/b912e32994e4d278eec8a99b788d3ec3 to your computer and use it in GitHub Desktop.
Save clbarnes/b912e32994e4d278eec8a99b788d3ec3 to your computer and use it in GitHub Desktop.
GCRA rate limiting algorithm implemented as a redis lua script
--[[
Load the script from this file into redis, storing its SHA1 hash as an environment variable
$ SCRIPT_SHA=$(redis-cli -x script load < gcra.lua)
Run the script by addressing its hash, with 1 key (as used by this script) called `myratelimitkey`,
with a rate limit of 2 attempts every 1 000 milliseconds (1 second).
$ redis-cli EVALSHA $SCRIPT_SHA 1 myratelimitkey 2 1000
Returns 1 if the request is limited; 0 if not.
]]
local key = KEYS[1]
local count = tonumber(ARGV[1])
local period_ms = tonumber(ARGV[2])
local separation = period_ms / count
local now = redis.call('TIME')
-- convert { s, us } to single ms value
local now_ms = tonumber(now[1]) * 1000 + tonumber(now[2]) / 1000
-- if no value is stored, use now
local m_stored = redis.call('GET', key) or now_ms
-- must be now or in future
local theoretical_arrival_time = math.max(now_ms, tonumber(m_stored))
-- therefore, must be >=0
local ms_until_tat = theoretical_arrival_time - now_ms
local threshold_duration = period_ms - separation
local ms_until_release = ms_until_tat - threshold_duration
if (ms_until_release > 0) then
return ms_until_release
end
local new_arrival_time = theoretical_arrival_time + separation
redis.call('SET', key, new_arrival_time)
return 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment