This commit is contained in:
jjbrunton committed 2026-01-04 19:16:31 +00:00
commit c552956516
23 files changed
+5193

No files matched your search

+66
View File
@@ -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),
};
}
}