Implement Sequential Rate Limiting

This commit is contained in:
Amish Shah
2016-08-19 18:01:24 +01:00
parent 392133f927
commit dcba580d89
9 changed files with 122 additions and 84 deletions

View File

@@ -0,0 +1,71 @@
const RequestHandler = require('./RequestHandler');
/**
* Handles API Requests sequentially, i.e. we wait until the current request is finished before moving onto
* the next. This plays a _lot_ nicer in terms of avoiding 429's when there is more than one session of the account,
* but it can be slower.
* @extends {RequestHandler}
*/
module.exports = class SequentialRequestHandler extends RequestHandler {
constructor(restManager) {
super(restManager);
/**
* Whether this rate limiter is waiting for a response from a request
* @type {Boolean}
*/
this.waiting = false;
}
push(request) {
super.push(request);
this.handle();
}
/**
* Performs a request then resolves a promise to indicate its readiness for a new request
* @param {APIRequest} item the item to execute
* @returns {Promise<Object, Error>}
*/
execute(item) {
return new Promise((resolve, reject) => {
item.request.gen().end((err, res) => {
if (res && res.headers) {
this.requestLimit = res.headers['x-ratelimit-limit'];
this.requestResetTime = Number(res.headers['x-ratelimit-reset']) * 1000;
this.requestRemaining = Number(res.headers['x-ratelimit-remaining']);
}
if (err) {
this.waiting = false;
item.reject(err);
reject(err);
} else {
this.queue.shift();
const data = res && res.body ? res.body : {};
item.resolve(data);
if (this.requestRemaining === 0) {
setTimeout(() => {
this.waiting = false;
resolve(data);
}, (this.requestResetTime - Date.now()) + 4000);
} else {
this.waiting = false;
resolve(data);
}
}
});
});
}
handle() {
super.handle();
if (this.waiting || this.queue.length === 0) {
return;
}
this.waiting = true;
const item = this.queue[0];
this.execute(item).then(() => this.handle()).catch(console.log);
}
};