Skip to content

Commit

Permalink
Merge pull request #2 from AScripnic/patch-1
Browse files Browse the repository at this point in the history
Add Exponential Backoff on each request
  • Loading branch information
AlexanderC authored Jun 25, 2019
2 parents 236d4b7 + 97c3fd0 commit fc9cc5a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 13 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
"mocha": "^5.2.0"
},
"dependencies": {
"axios": "^0.18.0",
"axios": "^0.19.0",
"debug": "^4.1.0",
"merge-options": "^1.0.1"
"merge-options": "^1.0.1",
"promise-retry": "^1.1.1"
}
}
7 changes: 5 additions & 2 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ class Api {
* @param {*} endpoints
* @param {string} token
* @param {string} key
* @param {object} opts
*/
constructor(namespace, endpoints, token, key) {
constructor(namespace, endpoints, token, key, opts) {
this.namespace = namespace;
this._endpoints = endpoints;
this.token = token;
this.key = key;
this.opts = opts;

debug(`endpoints:${this.namespace}`, this.endpoints);
}
Expand All @@ -32,7 +34,8 @@ class Api {
`${this.namespace}:${endpoint}`,
this._endpoints[endpoint],
this.token,
this.key
this.key,
this.opts
);
}

Expand Down
22 changes: 17 additions & 5 deletions src/endpoint.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const axios = require('axios');
const promiseRetry = require('promise-retry');
const debug = require('./utils/debug')(__filename);
const Response = require('./response');

Expand All @@ -8,14 +9,16 @@ class Endpoint {
* @param {*} definition
* @param {string} token
* @param {string} key
* @param {object} opts
*/
constructor(name, definition, token, key) {
constructor(name, definition, token, key, opts) {
this.name = name;
this.definition = definition;
this.token = token;
this.key = key;
this.opts = opts;

debug(`endpoint:${this.name}`, this.definition);
debug(`endpoint:${ this.name }`, this.definition);
}

/**
Expand All @@ -24,24 +27,33 @@ class Endpoint {
* @returns {Response}
*/
async call(...args) {
const { name } = this;
const opts = await this.definition.build(
this.definition,
this.token,
this.key,
...args
);

debug(`call:${this.name}`, opts);
debug(`call:${ name }`, opts);

let response = null;

try {
response = new Response(this, opts, null, await axios.request(opts));
const result = await promiseRetry(this.opts.backoff, async (retry, number) => {
debug(`call:${ name }:try:${ number }`, opts);

const response = await axios.request(opts);

return response.status === 429 ? retry(response) : response;
});

response = new Response(this, opts, null, result);
} catch (error) {
response = new Response(this, opts, error, null);
}

debug(`response:${this.name}`, response.toJSON());
debug(`response:${ name }`, response.toJSON());

return response;
}
Expand Down
37 changes: 33 additions & 4 deletions src/ubidots.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const mergeOptions = require('merge-options');

const { ApiBase, api: apigen } = require('./api-definition');
const Api = require('./api');
const debug = require('./utils/debug')(__filename);
Expand All @@ -6,11 +8,17 @@ const MissingApiNamespaceError = require('./error/missing-api-namespace');
class Ubidots {
/**
* @param {*} api
* @param {object} opts
* @param {object} opts.backoff - backoff options
* @param {number} opts.backoff.retries - amount of retries
* @param {number} opts.backoff.minTimeout - minimum amount of time between retries
* @param {number} opts.backoff.factor - factor of the timeout between retries
*/
constructor(api) {
constructor(api, opts) {
this._api = api;
this.token = null;
this.key = null;
this.opts = opts;

debug('namespaces', this.apis);
}
Expand Down Expand Up @@ -46,7 +54,8 @@ class Ubidots {
namespace,
this._api[namespace],
this.token,
this.key
this.key,
this.opts
);
}

Expand Down Expand Up @@ -78,14 +87,34 @@ class Ubidots {
/**
* Create an instance of Ubidots API Client
* @param {string} baseURL
* @param {object} opts
* @param {object} opts.backoff - backoff options
* @param {number=} opts.backoff.retries - amount of retries
* @param {number=} opts.backoff.minTimeout - minimum amount of time between retries
* @param {number=} opts.backoff.factor - factor of the timeout between retries
* @returns {Ubidots}
*/
static create(baseURL = ApiBase.Industrial) {
static create(baseURL = ApiBase.Industrial, opts = Ubidots.DEFAULT_CONFIG) {
debug('client', baseURL);

const api = apigen(baseURL);

return new this(api);
const mergedOpts = mergeOptions(this.DEFAULT_CONFIG, opts);

return new this(api, mergedOpts);
}

/**
* @returns {{backoff: {minTimeout: number, retries: number, factor: number}}}
*/
static get DEFAULT_CONFIG() {
return {
backoff: {
retries: 5,
factor: 1.4,
minTimeout: 500,
}
};
}
}

Expand Down

0 comments on commit fc9cc5a

Please sign in to comment.