Initial
This commit is contained in:
commit
c552956516
23 files changed
+5193
No files matched your search
@@ -0,0 +1,66 @@
|
||||
import PQueue from 'p-queue';
|
||||
import type { Config } from '../config/index.js';
|
||||
import type { Logger } from './logger.js';
|
||||
|
||||
export class RateLimiter {
|
||||
private queue: PQueue;
|
||||
private lastMessageTime: number = 0;
|
||||
private messagesThisHour: number = 0;
|
||||
private hourStartTime: number = Date.now();
|
||||
|
||||
constructor(
|
||||
private config: Config,
|
||||
private logger: Logger
|
||||
) {
|
||||
this.queue = new PQueue({ concurrency: 1 });
|
||||
}
|
||||
|
||||
async throttle<T>(fn: () => Promise<T>): Promise<T> {
|
||||
return this.queue.add(async () => {
|
||||
const now = Date.now();
|
||||
|
||||
// Reset hourly counter if needed
|
||||
if (now - this.hourStartTime > 3600000) {
|
||||
this.messagesThisHour = 0;
|
||||
this.hourStartTime = now;
|
||||
this.logger.debug('Hourly rate limit counter reset');
|
||||
}
|
||||
|
||||
// Check hourly limit
|
||||
if (this.messagesThisHour >= this.config.rateLimit.maxMessagesPerHour) {
|
||||
const waitTime = 3600000 - (now - this.hourStartTime);
|
||||
this.logger.info(`Hourly limit reached, waiting ${Math.round(waitTime / 60000)} minutes`);
|
||||
await this.sleep(waitTime);
|
||||
this.messagesThisHour = 0;
|
||||
this.hourStartTime = Date.now();
|
||||
}
|
||||
|
||||
// Enforce minimum delay with jitter
|
||||
const timeSinceLastMessage = now - this.lastMessageTime;
|
||||
const minDelay = this.config.rateLimit.minDelayBetweenMessagesMs;
|
||||
const jitter = Math.random() * this.config.rateLimit.jitterMs;
|
||||
|
||||
if (this.lastMessageTime > 0 && timeSinceLastMessage < minDelay) {
|
||||
const waitTime = minDelay - timeSinceLastMessage + jitter;
|
||||
this.logger.debug(`Rate limiting: waiting ${Math.round(waitTime / 1000)} seconds`);
|
||||
await this.sleep(waitTime);
|
||||
}
|
||||
|
||||
this.lastMessageTime = Date.now();
|
||||
this.messagesThisHour++;
|
||||
|
||||
return fn();
|
||||
}) as Promise<T>;
|
||||
}
|
||||
|
||||
private sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
getStats(): { messagesThisHour: number; minutesSinceLastMessage: number } {
|
||||
return {
|
||||
messagesThisHour: this.messagesThisHour,
|
||||
minutesSinceLastMessage: Math.round((Date.now() - this.lastMessageTime) / 60000),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user