Skip to content

Instantly share code, notes, and snippets.

@davidpurkiss
Last active January 29, 2019 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidpurkiss/191c4dbb714154e42b5ca4f8a8fc0cf1 to your computer and use it in GitHub Desktop.
Save davidpurkiss/191c4dbb714154e42b5ca4f8a8fc0cf1 to your computer and use it in GitHub Desktop.
import moment = require('moment');
export class RequestThrottler {
requestTimes: moment.Moment[];
requestRateLimit: number;
requestRateWindow: moment.Duration;
pendingRequests: {
resolve: (value?: any) => void;
reject: (reason?: any) => void;
request: () => Promise<any>;
}[];
timer: NodeJS.Timer;
constructor(requestRateLimit: number, requestRateWindowInMilliseconds: number) {
this.requestRateLimit = requestRateLimit;
this.requestRateWindow = moment.duration(requestRateWindowInMilliseconds);
this.requestTimes = [];
this.pendingRequests = [];
}
async execute(request: () => Promise<any>): Promise<any> {
if (this.currentRequestRate < this.requestRateLimit) {
this.requestTimes.push(moment());
return await request();
} else {
this.scheduleCheckPendingRequests();
return new Promise<any>(async (resolve, reject) => {
this.pendingRequests.push({
resolve: resolve,
reject: reject,
request: request
});
});
}
}
private async scheduleCheckPendingRequests() {
this.timer = setTimeout(async () => {
this.checkPendingRequests();
}, 100);
}
private async checkPendingRequests() {
if (this.pendingRequests.length === 0) {
this.scheduleCheckPendingRequests();
return;
}
if (this.currentRequestRate < this.requestRateLimit) {
const pendingRequestsToExecute = this.requestRateLimit - this.currentRequestRate;
let requestsToExecute = this.pendingRequests.slice(0, pendingRequestsToExecute);
this.pendingRequests = this.pendingRequests.slice(pendingRequestsToExecute + 1, this.pendingRequests.length);
for (let request of requestsToExecute) {
try {
this.requestTimes.push(moment());
request.resolve(await request.request());
} catch (error) {
request.reject(error);
}
}
this.scheduleCheckPendingRequests();
} else {
this.scheduleCheckPendingRequests();
}
}
get currentRequestRate(): number {
return this.requestTimes.filter(t => t.isSameOrAfter(moment().subtract(this.requestRateWindow))).length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment