Skip to content

Commit c89e3a3

Browse files
authored
feat: rateLimit() replace raw Map with TTLCache to remove manual cleanup logic [ GSSOC'26 ] (JhaSourav07#1137)
## Description Fixes JhaSourav07#1135 The `rateLimit()` function used a raw `Map` with manual periodic cleanup to handle expiry and capacity. `TTLCache` is already imported in the same file and handles both automatically. This PR replaces the raw Map with a `TTLCache` instance, removing ~15 lines of manual cleanup logic and making the implementation consistent with the existing `RateLimiter` class. ## Pillar - [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview N/A — internal rate limiting logic, no visual output. ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally. - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors. - [x] My commits follow the Conventional Commits format. - [x] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have starred the repo. - [x] I have made sure that I have only one commit to merge in this PR. - [ ] The SVG output matches the CommitPulse "premium quality" aesthetic standard. - [ ] (Recommended) I joined the CommitPulse Discord community.
2 parents ece8397 + aecbcd5 commit c89e3a3

1 file changed

Lines changed: 7 additions & 29 deletions

File tree

lib/rate-limit.ts

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,8 @@ interface RateLimitResult {
4545
reset: number;
4646
}
4747

48-
const trackers = new Map<string, { count: number; expires: number }>();
48+
const trackers = new TTLCache<{ count: number }>(2000, 60000);
4949

50-
/**
51-
* Checks if a request from a given IP should be rate limited.
52-
*
53-
* @param ip The IP address to track
54-
* @param limit Maximum number of requests allowed in the window
55-
* @param windowMs Time window in milliseconds
56-
* @returns RateLimitResult
57-
*/
5850
export function rateLimit(
5951
ip: string,
6052
limit: number = 60,
@@ -63,46 +55,32 @@ export function rateLimit(
6355
const now = Date.now();
6456
const tracker = trackers.get(ip);
6557

66-
// Periodic cleanup of the map to prevent memory leaks.
67-
// We perform a partial cleanup if the map grows too large.
68-
if (trackers.size > 2000) {
69-
let cleaned = 0;
70-
for (const [key, value] of trackers.entries()) {
71-
if (now > value.expires) {
72-
trackers.delete(key);
73-
cleaned++;
74-
}
75-
// Stop cleaning after some work to avoid blocking the request for too long
76-
if (cleaned > 500) break;
77-
}
78-
}
79-
80-
if (!tracker || now > tracker.expires) {
81-
const expires = now + windowMs;
82-
trackers.set(ip, { count: 1, expires });
58+
if (!tracker) {
59+
trackers.set(ip, { count: 1 }, windowMs);
8360
return {
8461
success: true,
8562
limit,
8663
remaining: limit - 1,
87-
reset: expires,
64+
reset: now + windowMs,
8865
};
8966
}
9067

9168
tracker.count++;
69+
trackers.set(ip, tracker, windowMs);
9270

9371
if (tracker.count > limit) {
9472
return {
9573
success: false,
9674
limit,
9775
remaining: 0,
98-
reset: tracker.expires,
76+
reset: now + windowMs,
9977
};
10078
}
10179

10280
return {
10381
success: true,
10482
limit,
10583
remaining: limit - tracker.count,
106-
reset: tracker.expires,
84+
reset: now + windowMs,
10785
};
10886
}

0 commit comments

Comments
 (0)