UNPKG

redis-sliding-rate-limiter

Version:

Flexible and performant rate limiter based on sliding window algorithm with arbitrary precision

3 lines (2 loc) 2.18 kB
declare const LuaScript = "\n local key = KEYS[1]\n local window = tonumber(ARGV[1])\n local microsecFactor = tonumber(ARGV[2])\n local expire_ms = tonumber(ARGV[3])\n local limit = tonumber(ARGV[4])\n local limit_overhead = tonumber(ARGV[5])\n \n local now = redis.call('TIME') -- Array with seconds and microseconds for the current time\n local now_microsec = now[1] * 1000000 + now[2] -- Timestamp in microseconds\n local now_ms = math.floor(now_microsec * 0.001) -- Timestamp in milliseconds\n local member_score = math.floor(now_microsec * microsecFactor) -- Compute member score (timestamp) at the right subdivision unit using the conversion factor\n local window_expire_at = now_ms + expire_ms -- Window expiration epoch in milliseconds\n \n -- Remove elements older than (now - window) at the given subdivision unit\n redis.call('ZREMRANGEBYSCORE', key, 0, member_score - window)\n \n -- Get number of requests in the current window\n local current_requests_count = redis.call('ZCARD', key)\n \n -- Compute the number of remaining requests allowed in the current window\n local remaining_allowed_requests = limit - current_requests_count\n \n -- If greater than zero (plus limit overhead), allow request\n local allow_request = (remaining_allowed_requests + limit_overhead) > 0\n \n if allow_request then\n redis.call('ZADD', key, member_score, now_microsec)\n end\n \n -- Compute epoch (in milliseconds) at which the first element will expire in the current window\n local first_expire_at = -1\n \n if current_requests_count > 0 then\n local first_member = redis.call('ZRANGE', key, 0, 0)[1] -- Return the first element member (microseconds)\n first_expire_at = math.floor(first_member * 0.001) + expire_ms -- Extract milliseconds from member and add expiration time\n else\n first_expire_at = window_expire_at\n end\n \n -- Expire the whole key for cleanup (ms)\n redis.call('PEXPIRE', key, expire_ms)\n \n return {allow_request, remaining_allowed_requests - 1, first_expire_at, window_expire_at}\n"; export { LuaScript };