Skip to content

Commit 1aacdab

Browse files
committed
perf: optimize lua
1 parent 668e7f9 commit 1aacdab

File tree

1 file changed

+47
-27
lines changed

1 file changed

+47
-27
lines changed

src/index.js

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,65 @@ module.exports = class Limiter {
2121
local max = tonumber(ARGV[3])
2222
local start = now - duration * 1000
2323
24-
-- Remove expired entries
25-
redis.call('zremrangebyscore', key, 0, start)
24+
-- Check if the key exists
25+
local exists = redis.call('EXISTS', key)
2626
27-
-- Get current count
28-
local count = redis.call('zcard', key)
27+
local count = 0
28+
local oldest = now
2929
30-
-- Calculate remaining
31-
local remaining = max - count
30+
if exists == 1 then
31+
-- Remove expired entries based on the current duration
32+
redis.call('ZREMRANGEBYSCORE', key, 0, start)
3233
33-
-- Add current request
34-
redis.call('zadd', key, now, now)
34+
-- Get count
35+
count = redis.call('ZCARD', key)
3536
36-
-- Optimize: Only fetch oldest entry if we need it
37-
local oldest
38-
local oldest_result = redis.call('zrange', key, 0, 0)
39-
oldest = #oldest_result > 0 and tonumber(oldest_result[1]) or now
37+
-- Get oldest timestamp if we have entries
38+
if count > 0 then
39+
local oldest_result = redis.call('ZRANGE', key, 0, 0)
40+
oldest = tonumber(oldest_result[1])
41+
end
42+
end
4043
41-
-- Optimize: Only fetch oldestInRange if count is at or above max
42-
local oldestInRange = now
43-
if count >= max then
44-
local oldest_in_range_result = redis.call('zrange', key, -max, -max)
45-
oldestInRange = #oldest_in_range_result > 0 and tonumber(oldest_in_range_result[1]) or now
44+
-- Calculate remaining (before adding current request)
45+
local remaining = max - count
46+
47+
-- Early return if already at limit
48+
if remaining <= 0 then
49+
local resetMicro = oldest + duration * 1000
50+
return {0, math.floor(resetMicro / 1000000), max}
4651
end
4752
48-
-- Calculate reset time
49-
local resetMicro = (oldestInRange ~= now and oldestInRange or oldest) + duration * 1000
53+
-- Add current request with current timestamp
54+
redis.call('ZADD', key, now, now)
55+
56+
-- Calculate reset time and handle trimming if needed
57+
local resetMicro
5058
51-
-- Optimize: Only trim if necessary
59+
-- Only perform trim if we're at or over max (based on count before adding)
5260
if count >= max then
53-
redis.call('zremrangebyrank', key, 0, -(max + 1))
61+
-- Get the entry at position -max for reset time calculation
62+
local oldest_in_range_result = redis.call('ZRANGE', key, -max, -max)
63+
local oldestInRange = oldest
64+
65+
if #oldest_in_range_result > 0 then
66+
oldestInRange = tonumber(oldest_in_range_result[1])
67+
end
68+
69+
-- Trim the set
70+
redis.call('ZREMRANGEBYRANK', key, 0, -(max + 1))
71+
72+
-- Calculate reset time based on the entry at position -max
73+
resetMicro = oldestInRange + duration * 1000
74+
else
75+
-- We're under the limit, use the oldest entry for reset time
76+
resetMicro = oldest + duration * 1000
5477
end
5578
56-
-- Set expiration
57-
redis.call('pexpire', key, duration)
58-
59-
-- Ensure remaining is never negative
60-
if remaining < 0 then remaining = 0 end
79+
-- Set expiration using the provided duration
80+
redis.call('PEXPIRE', key, duration)
6181
62-
return {remaining, resetMicro / 1000000, max}
82+
return {remaining, math.floor(resetMicro / 1000000), max}
6383
`
6484
})
6585
}

0 commit comments

Comments
 (0)