-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsliding-window-counter.js
81 lines (70 loc) · 2.26 KB
/
sliding-window-counter.js
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
export default class SlidingWindowCounter {
constructor(windowSize, maxRequests, redisClient) {
this.windowSize = windowSize * 1000; // in milliseconds
this.maxRequests = maxRequests;
this.redisClient = redisClient;
this.redisKey = "rate_limit:global";
this.previousWindowCount = this.redisClient.set(
`${this.redisKey}:previousWindowCount`,
0
);
this.currentWindowCount = this.redisClient.set(
`${this.redisKey}:currentWindowCount`,
0
);
this.windowStartTime = this.redisClient.set(
`${this.redisKey}:windowStartTime`,
Date.now()
);
}
async handleRequest() {
const currentTime = Date.now();
let windowStartTime = Number(
await this.redisClient.get(`${this.redisKey}:windowStartTime`)
);
const elapsedTime = currentTime - windowStartTime;
let previousWindowCount = Number(
await this.redisClient.get(`${this.redisKey}:previousWindowCount`)
);
let currentWindowCount = Number(
await this.redisClient.get(`${this.redisKey}:currentWindowCount`)
);
if (elapsedTime > this.windowSize) {
const windowsElapsed = Math.floor(elapsedTime / this.windowSize);
if (windowsElapsed > 1) {
previousWindowCount = 0;
} else {
previousWindowCount = currentWindowCount;
}
currentWindowCount = 0;
windowStartTime += windowsElapsed * this.windowSize;
await this.redisClient.set(
`${this.redisKey}:previousWindowCount`,
previousWindowCount
);
await this.redisClient.set(
`${this.redisKey}:currentWindowCount`,
currentWindowCount
);
await this.redisClient.set(
`${this.redisKey}:windowStartTime`,
windowStartTime
);
}
const currentWindowPercentage =
((currentTime - windowStartTime) / this.windowSize) * 100;
const previousWindowPercentage = 100 - currentWindowPercentage;
const totalRequestsInWindow =
currentWindowCount +
(previousWindowPercentage * previousWindowCount) / 100;
if (totalRequestsInWindow >= this.maxRequests) {
return false;
}
currentWindowCount++;
await this.redisClient.set(
`${this.redisKey}:currentWindowCount`,
currentWindowCount
);
return true;
}
}