diff --git a/README.md b/README.md index ebc8beb..773443c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ var options = { retry : 2, // will retry the call twice, in case of error. verbose_logging : false, // will log errors only, if set to be true, will log all actions accepted: [ 400, 404 ] // Accepted HTTP Status codes (will not retry if request response has any of these HTTP Status Code) + delay: 2000 // will delay retries by 2000 ms. The default is 100. + factor: 2 // will multiple the delay by the factor each time a retry is attempted. }; rp(options) diff --git a/index.js b/index.js index 4a711e5..c2d31ec 100644 --- a/index.js +++ b/index.js @@ -10,7 +10,18 @@ class rpRetry { } const tries = options.retry || 1; delete options.retry; - const fetchDataWithRetry = tryCount => { + + const delay = options.delay || 100; // default ms delay between retries + delete options.delay; + + const factor = options.factor || 1; // If absent, delay will always be the same. + delete options.factor; + + if (options.verbose_logging) { + logger.info(`calling ${options.uri} with retry ${tries}, initial delay=${delay}, factor=${factor}`); + } + + const fetchDataWithRetry = (tryCount, delay) => { return requestPromise(options) .then(result => { if (options.verbose_logging) { @@ -28,12 +39,17 @@ class rpRetry { logger.info(`Encountered error ${err.message} for ${options.method} request to ${options.uri}, retry count ${tryCount}`); tryCount -= 1; if (tryCount) { - return fetchDataWithRetry(tryCount); + return new Promise((resolve, reject) => { + setTimeout(() => { + logger.debug(`waiting for ${delay} ms before next retry for ${options.uri}. Next wait ${delay * factor}`); + resolve(fetchDataWithRetry(tryCount, delay * factor)); + }, delay); + }); } return Promise.reject(err); }); }; - return fetchDataWithRetry(tries); + return fetchDataWithRetry(tries, delay); } static _rp(options) { diff --git a/package.json b/package.json index d224838..2b77abb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "main": "index.js", "scripts": { "test": "node_modules/gulp/bin/gulp.js test", - "coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" + "coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls", + "eslint": "eslint test/. index.js", + "eslint-fix": "eslint test/. index.js --fix" }, "repository": { "type": "git", @@ -45,6 +47,7 @@ "chai": "^4.1.2", "chai-subset": "^1.6.0", "coveralls": "^3.0.0", + "eslint": "^5.5.0", "gulp": "^3.9.1", "gulp-eslint": "^4.0.0", "gulp-if": "^2.0.2", diff --git a/test/index.test.js b/test/index.test.js index c79c58e..0dd5365 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -114,6 +114,19 @@ describe('request-promise-retry', function () { expect(data.error).equal(undefined); }); }); + it('should pass, retry with exponential backoff', () => { + // failure should take a bit of time to happen + const startTime = new Date(); + return rp({ + uri: 'http://adadadadad.com/', + method: 'GET', + retry: 4, + delay: 30, + factor: 10 // 0 + 30 + 300 + 3000 + }) + .catch(error => { + expect(new Date() - startTime).to.be.above(0 + 30 + 300 + 3000); + }); it('should not retry, accepted options enabled', () => { return rp(optionsDontRetryAcceptedOptions) .catch(data => {