add overall more stability
This commit is contained in:
@@ -5,10 +5,26 @@ function pruneBucket(bucket, windowMs, now) {
|
||||
}
|
||||
}
|
||||
|
||||
export function createRateLimiter({windowMs, max, keyGenerator, message}) {
|
||||
export function createRateLimiter({windowMs, max, keyGenerator, message, cleanupIntervalMs = 60 * 1000}) {
|
||||
const hits = new Map();
|
||||
let cleanupTimer = null;
|
||||
|
||||
return (req, res, next) => {
|
||||
const cleanup = () => {
|
||||
const now = Date.now();
|
||||
for (const [key, bucket] of hits) {
|
||||
pruneBucket(bucket, windowMs, now);
|
||||
if (!bucket.length) {
|
||||
hits.delete(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (cleanupIntervalMs > 0) {
|
||||
cleanupTimer = setInterval(cleanup, cleanupIntervalMs);
|
||||
cleanupTimer.unref();
|
||||
}
|
||||
|
||||
const limiter = (req, res, next) => {
|
||||
const key = keyGenerator(req);
|
||||
if (!key) {
|
||||
return next();
|
||||
@@ -17,6 +33,9 @@ export function createRateLimiter({windowMs, max, keyGenerator, message}) {
|
||||
const now = Date.now();
|
||||
const bucket = hits.get(key) || [];
|
||||
pruneBucket(bucket, windowMs, now);
|
||||
if (!bucket.length) {
|
||||
hits.delete(key);
|
||||
}
|
||||
if (bucket.length >= max) {
|
||||
return res.status(429).json({error: message});
|
||||
}
|
||||
@@ -25,4 +44,14 @@ export function createRateLimiter({windowMs, max, keyGenerator, message}) {
|
||||
hits.set(key, bucket);
|
||||
return next();
|
||||
};
|
||||
|
||||
limiter.close = () => {
|
||||
if (cleanupTimer) {
|
||||
clearInterval(cleanupTimer);
|
||||
cleanupTimer = null;
|
||||
}
|
||||
hits.clear();
|
||||
};
|
||||
|
||||
return limiter;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user