congress-dot-gov
Version:
TypeScript SDK for the Congress.gov API
64 lines (62 loc) • 2.23 kB
JavaScript
class AdaptiveRateLimiter {
config;
lastRequestTime = 0;
currentDelay = 0;
hourStartTime = Date.now();
constructor(config = {}) {
this.config = {
safetyMargin: config.safetyMargin ?? 0.1,
// 10% safety margin
minDelay: config.minDelay ?? 50,
// 50ms minimum
maxDelay: config.maxDelay ?? 3e4
// 30 seconds maximum
};
this.currentDelay = this.config.minDelay;
}
/**
* Call this before making an API request. It will wait the appropriate
* amount of time based on current rate limit status.
* @returns A promise that resolves when the next request can be made
*/
async waitForNextRequest() {
const now = Date.now();
if (now - this.hourStartTime >= 36e5) {
this.hourStartTime = now;
this.currentDelay = this.config.minDelay;
}
const timeSinceLastRequest = now - this.lastRequestTime;
const delayNeeded = this.currentDelay - timeSinceLastRequest;
if (delayNeeded > 0) {
await this.sleep(delayNeeded);
}
this.lastRequestTime = Date.now();
}
/**
* Calculate delay based on amount of time remaining in the hour and number of requests remaining
* @param rateLimitInfo - The current rate limit info
* @param currentTime - The current time
* @returns The delay in milliseconds
*/
calculateDelay(rateLimitInfo, currentTime) {
const { limit, remaining } = rateLimitInfo;
const timeElapsedThisHour = currentTime - this.hourStartTime;
const timeRemainingInHour = Math.max(100, 36e5 - timeElapsedThisHour);
const safeRemaining = Math.floor(limit * this.config.safetyMargin);
if (remaining <= safeRemaining) {
return this.config.maxDelay;
}
const optimalDelay = timeRemainingInHour / remaining;
const utilizationRatio = 1 - remaining / limit;
const adaptiveDelay = optimalDelay * utilizationRatio;
return Math.max(this.config.minDelay, Math.min(this.config.maxDelay, adaptiveDelay));
}
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
updateRateLimitInfo(rateLimitInfo) {
this.currentDelay = this.calculateDelay(rateLimitInfo, Date.now());
this.lastRequestTime = Date.now();
}
}
export { AdaptiveRateLimiter };