-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrateLimiter.ts
40 lines (39 loc) · 1.06 KB
/
rateLimiter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Redis } from 'ioredis'
/**
* Limits a rate of calls for given function in the given time interval
* see https://redis.io/commands/incr#pattern-rate-limiter-2
* @param redis
* @param fn - Rate limited function
* @param key - Redis key for rate limiter
* @param intervalMs in milliseconds - Interval
* @param limit - How many calls per interval are allowed
*/
export const rateLimiter = <Fn extends (...args: any[]) => any>(
redis: Redis,
fn: Fn,
key: string,
intervalMs: number,
limit = 1
): ((
...args: Parameters<Fn>
) => Promise<{ called: boolean; returnValue?: ReturnType<Fn> }>) => {
return async (...args: Parameters<Fn>) => {
const calls = (await redis.eval(
`
local current
current = redis.call("incr",KEYS[1])
if tonumber(current) == 1 then
redis.call("pexpire",KEYS[1],KEYS[2])
end
return current
`,
2,
key,
intervalMs
)) as number
if (calls <= limit) {
return { called: true, returnValue: await fn(...args) }
}
return { called: false }
}
}