From 9e871f5a9095c3afaf25b8bc688f52f22b8f074a Mon Sep 17 00:00:00 2001 From: ilsemaj Date: Fri, 29 Jan 2021 11:02:35 -0800 Subject: [PATCH] Bug fix for Issue #28 & enhancement for #24 (#32) * Adding reservoir limitations * Fix reservoir strategy bug & add custom timeout Co-authored-by: James Li --- README.fr.md | 5 +++++ README.md | 6 ++++++ README.zh-tw.md | 6 ++++++ lib/Methods.js | 29 +++++++++++++++++++++++++---- lib/constants.js | 2 +- lib/onfleet.js | 7 +++++-- package-lock.json | 2 +- package.json | 2 +- 8 files changed, 50 insertions(+), 9 deletions(-) diff --git a/README.fr.md b/README.fr.md index cca36e4..93884b5 100644 --- a/README.fr.md +++ b/README.fr.md @@ -62,6 +62,11 @@ Pour commencer à utiliser l'API Onfleet, il vous suffit de créer un objet Onfl ```js const onfleet = new Onfleet(''); ``` +En tant que champ facultatif, vous pouvez introduire un délai d'expiration personnalisé inférieur à la valeur par défaut de 70000 ms (délai d'expiration de l'API Onfleet par défaut) en fournissant un 2ème paramètre: +```js +const onfleet = new Onfleet('', 30000) // Cela mettra vos wrappers à expiration à 30000ms au lieu de 70000ms +``` + ### Authentification Une fois que l'objet Onfleet est créé, vous pouvez utiliser une fonction utilitaire pour tester le noeud final d'authentification. Cette fonction renvoie un booléen: ```js diff --git a/README.md b/README.md index 5cf586c..2d3622d 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,12 @@ To start utilizing the Onfleet API, you simply need to create an Onfleet object ```js const onfleet = new Onfleet(''); ``` + +As an optional field, you can introduce a customized timeout that is less than the default 70000ms (default Onfleet API timeout) by providing a 2nd parameter: +```js +const onfleet = new Onfleet('', 30000) // This will set your wrappers to timeout at 30000ms instead of 70000ms +``` + ### Authentication Once the Onfleet object is created, you can use a utility function to test on the authentication endpoint, this function returns a boolean: ```js diff --git a/README.zh-tw.md b/README.zh-tw.md index f990efc..5579b11 100644 --- a/README.zh-tw.md +++ b/README.zh-tw.md @@ -64,6 +64,12 @@ npm install @types/onfleet__node-onfleet ```js const onfleet = new Onfleet(''); ``` + +由於某些應用的執行逾時參數較低(例如Heroku的三十秒設定),您可以在創立物件時,提供一個低於70000ms、客製化的逾時參數: +```js +const onfleet = new Onfleet('', 30000) // 在此設定執行逾時參數為30000ms +``` + ### 金鑰認證 當Onfleet物件成功被創建,表示您的應用程式介面金鑰是符合預期的。您可以嘗試使用verifyKey函式來測試您的金鑰是否合法,authentication這個endpoint會認證您的金鑰,回應為一布林值: ```js diff --git a/lib/Methods.js b/lib/Methods.js index ebac37b..87d22ee 100644 --- a/lib/Methods.js +++ b/lib/Methods.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ const Bottleneck = require('bottleneck'); const fetch = require('node-fetch'); const constants = require('./constants'); @@ -12,7 +13,6 @@ const { // Create new rate limiter using defined constants const limiter = new Bottleneck({ reservoir: constants.LIMITER_RESERVOIR, - reservoirRefreshInterval: constants.LIMITER_REFRESH_INTERVAL, maxConcurrent: constants.LIMITER_MAX_CONCURRENT, minTime: constants.LIMITER_MIN_TIME, }); @@ -22,11 +22,19 @@ const limiter = new Bottleneck({ const reassignRate = (newRate) => { if (newRate > 0) { limiter.updateSettings({ - reservoirRefreshAmount: newRate, + reservoir: newRate, }); } }; +const wait = (ms) => { + console.log('Waiting due to rate limiting'); + // eslint-disable-next-line no-new + new Promise((resolve) => { + setTimeout(resolve, ms); + }); +}; + /** * The Method Factory * @desc configures the actual method for each CRUD operations @@ -101,8 +109,21 @@ const Methods = (key, api, ...args) => { timeout: timeoutInMilliseconds, body: hasBody ? JSON.stringify(body) : undefined, }).then((res) => { - // On response, update the rate - reassignRate(res.headers.get('x-ratelimit-remaining')); + // On reservoir depletion, we wait 10000ms and reset the rate again (20 req/second limitation) + limiter.on('depleted', (empty) => { + if (!empty) { + wait(constants.LIMITER_WAIT_UPON_DEPLETION).then(() => { + reassignRate(constants.LIMITER_RESERVOIR); + }); + } + }); + // For every request, we compare the reservoir with the remainding rate limit in the header + limiter.currentReservoir() + .then((reservoir) => { + if (reservoir < res.headers.get('x-ratelimit-remaining')) { + reassignRate(res.headers.get('x-ratelimit-remaining')); + } + }); if (res.ok) { // Return status code for deletion as the API does, else, return the body of the response diff --git a/lib/constants.js b/lib/constants.js index 48d4b60..593d482 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,6 +1,6 @@ const constants = { LIMITER_RESERVOIR: 20, - LIMITER_REFRESH_INTERVAL: 250, + LIMITER_WAIT_UPON_DEPLETION: 10000, LIMITER_MAX_CONCURRENT: 1, LIMITER_MIN_TIME: 50, }; diff --git a/lib/onfleet.js b/lib/onfleet.js index ca032d2..13dfc4e 100644 --- a/lib/onfleet.js +++ b/lib/onfleet.js @@ -25,14 +25,17 @@ resources.Webhooks = require('./resources/Webhooks'); */ class Onfleet { - constructor(apiKey) { + constructor(apiKey, userTimeout) { if (!apiKey) { throw new ValidationError('Onfleet API key not found, please obtain an API key from your organization admin'); + } if (userTimeout > 70000) { + throw new ValidationError('User-defined timeout has to be shorter than 70000ms'); } else { this.apiKey = apiKey; this.api = { baseUrl: `${DEFAULT_URL}${DEFAULT_PATH}/${DEFAULT_API_VERSION}`, - timeout: DEFAULT_TIMEOUT, + // eslint-disable-next-line no-unneeded-ternary + timeout: (userTimeout ? userTimeout : DEFAULT_TIMEOUT), headers: { 'Content-Type': 'application/json', 'User-Agent': `${name}-${version}`, diff --git a/package-lock.json b/package-lock.json index c2bc9e5..4b2c7ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@onfleet/node-onfleet", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f1bcc21..abcfa21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onfleet/node-onfleet", - "version": "1.1.1", + "version": "1.2.0", "description": "Official client library for accessing the Onfleet API", "main": "index.js", "scripts": {