fluxguard 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +555 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +125 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.js +522 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
- package/scripts/fixed_window.lua +15 -0
- package/scripts/sliding_window_counter.lua +22 -0
- package/scripts/sliding_window_log.lua +20 -0
- package/scripts/token_bucket.lua +26 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- KEYS[1]=prev KEYS[2]=curr
|
|
2
|
+
-- ARGV: limit, window_ms, now_ms
|
|
3
|
+
local limit = tonumber(ARGV[1])
|
|
4
|
+
local window = tonumber(ARGV[2])
|
|
5
|
+
local now = tonumber(ARGV[3])
|
|
6
|
+
local prev = tonumber(redis.call('GET', KEYS[1])) or 0
|
|
7
|
+
local curr = tonumber(redis.call('GET', KEYS[2])) or 0
|
|
8
|
+
local elapsed = now % window
|
|
9
|
+
local weight = 1 - (elapsed / window)
|
|
10
|
+
local estimated = math.floor(prev * weight) + curr
|
|
11
|
+
if estimated >= limit then
|
|
12
|
+
local currStart = now - elapsed
|
|
13
|
+
local reset = currStart + window
|
|
14
|
+
return {0, estimated, limit, reset, reset - now}
|
|
15
|
+
end
|
|
16
|
+
redis.call('INCR', KEYS[2])
|
|
17
|
+
redis.call('PEXPIRE', KEYS[2], window * 2)
|
|
18
|
+
redis.call('PEXPIRE', KEYS[1], window * 2)
|
|
19
|
+
local nextEst = estimated + 1
|
|
20
|
+
local currStart = now - elapsed
|
|
21
|
+
local reset = currStart + window
|
|
22
|
+
return {1, limit - nextEst, limit, reset, 0}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- KEYS[1] = zset key
|
|
2
|
+
-- ARGV: limit, window_ms, now_ms, member unique id
|
|
3
|
+
local limit = tonumber(ARGV[1])
|
|
4
|
+
local window = tonumber(ARGV[2])
|
|
5
|
+
local now = tonumber(ARGV[3])
|
|
6
|
+
local member = ARGV[4]
|
|
7
|
+
local cutoff = now - window
|
|
8
|
+
redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', cutoff)
|
|
9
|
+
local count = redis.call('ZCARD', KEYS[1])
|
|
10
|
+
if count >= limit then
|
|
11
|
+
local oldest = redis.call('ZRANGE', KEYS[1], 0, 0, 'WITHSCORES')
|
|
12
|
+
local ts = tonumber(oldest[2])
|
|
13
|
+
local reset = ts + window
|
|
14
|
+
return {0, 0, limit, reset, reset - now}
|
|
15
|
+
end
|
|
16
|
+
redis.call('ZADD', KEYS[1], now, member)
|
|
17
|
+
redis.call('PEXPIRE', KEYS[1], window * 2)
|
|
18
|
+
local newCount = count + 1
|
|
19
|
+
local reset = now + window
|
|
20
|
+
return {1, limit - newCount, limit, reset, 0}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- KEYS[1]=tokens KEYS[2]=last_refill
|
|
2
|
+
-- ARGV: limit(capacity), window_ms, now_ms
|
|
3
|
+
local capacity = tonumber(ARGV[1])
|
|
4
|
+
local window = tonumber(ARGV[2])
|
|
5
|
+
local now = tonumber(ARGV[3])
|
|
6
|
+
local refill = capacity / window
|
|
7
|
+
local tokens = tonumber(redis.call('GET', KEYS[1]))
|
|
8
|
+
local last = tonumber(redis.call('GET', KEYS[2]))
|
|
9
|
+
if not tokens then tokens = capacity end
|
|
10
|
+
if not last then last = now end
|
|
11
|
+
local delta = math.max(0, now - last)
|
|
12
|
+
tokens = math.min(capacity, tokens + delta * refill)
|
|
13
|
+
if tokens < 1 then
|
|
14
|
+
local need = 1 - tokens
|
|
15
|
+
local retry = math.ceil(need / refill)
|
|
16
|
+
local full = math.ceil(capacity / refill)
|
|
17
|
+
return {0, 0, capacity, now + full, retry}
|
|
18
|
+
end
|
|
19
|
+
tokens = tokens - 1
|
|
20
|
+
redis.call('SET', KEYS[1], tostring(tokens))
|
|
21
|
+
redis.call('SET', KEYS[2], tostring(now))
|
|
22
|
+
redis.call('PEXPIRE', KEYS[1], window * 3)
|
|
23
|
+
redis.call('PEXPIRE', KEYS[2], window * 3)
|
|
24
|
+
local remaining = math.floor(tokens)
|
|
25
|
+
local full = math.ceil((capacity - tokens) / refill)
|
|
26
|
+
return {1, remaining, capacity, now + full, 0}
|