Last active
April 7, 2025 08:52
-
-
Save clbarnes/b912e32994e4d278eec8a99b788d3ec3 to your computer and use it in GitHub Desktop.
GCRA rate limiting algorithm implemented as a redis lua script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
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