promise-poller
Advanced tools
Comparing version 1.0.3 to 1.1.0
@@ -11,2 +11,6 @@ 'use strict'; | ||
var _strategies = require('./strategies'); | ||
var _strategies2 = _interopRequireDefault(_strategies); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -17,3 +21,3 @@ | ||
var DEFAULTS = { | ||
interval: 1000, | ||
strategy: 'fixed-interval', | ||
retries: 5 | ||
@@ -27,2 +31,6 @@ }; | ||
if (typeof options.taskFn !== 'function') { | ||
throw new Error('No taskFn function specified in options'); | ||
} | ||
Object.keys(DEFAULTS).forEach(function (option) { | ||
@@ -34,6 +42,17 @@ return options[option] = options[option] || DEFAULTS[option]; | ||
if (typeof options.taskFn !== 'function') { | ||
throw new Error('No taskFn function specified in options'); | ||
if (!_strategies2.default[options.strategy]) { | ||
throw new Error('Invalid strategy "' + options.strategy + '". Valid strategies are ' + Object.keys(_strategies2.default)); | ||
} | ||
var strategy = _strategies2.default[options.strategy]; | ||
debug('(' + options.name + ') Using strategy "' + options.strategy + '".'); | ||
var strategyDefaults = strategy.defaults; | ||
Object.keys(strategyDefaults).forEach(function (option) { | ||
return options[option] = options[option] || strategyDefaults[option]; | ||
}); | ||
debug('(' + options.name + ') Options:'); | ||
Object.keys(options).forEach(function (option) { | ||
debug(' "' + option + '": ' + options[option]); | ||
}); | ||
return new _bluebird2.default(function (resolve, reject) { | ||
@@ -55,4 +74,7 @@ var retriesRemaining = options.retries; | ||
debug('(' + options.name + ') Poll failed. ' + retriesRemaining + ' retries remaining.'); | ||
debug('(' + options.name + ') Waiting ' + options.interval + 'ms to try again.'); | ||
_bluebird2.default.delay(options.interval).then(poll); | ||
var nextInterval = strategy.getNextInterval(options.retries - retriesRemaining, options); | ||
debug('(' + options.name + ') Waiting ' + nextInterval + 'ms to try again.'); | ||
_bluebird2.default.delay(nextInterval).then(poll); | ||
} | ||
@@ -59,0 +81,0 @@ }); |
'use strict'; | ||
function validateNumber(value, name) { | ||
if (typeof value !== 'number' || value <= 0) { | ||
throw new Error('"' + name + '" option must be a number greater than zero'); | ||
} | ||
} | ||
module.exports = { | ||
var strategies = { | ||
'fixed-interval': { | ||
@@ -14,4 +8,4 @@ defaults: { | ||
}, | ||
getNextInterval: function getNextInterval(options, attemptNumber, currentInterval) { | ||
return currentInterval; | ||
getNextInterval: function getNextInterval(count, options) { | ||
return options.interval; | ||
} | ||
@@ -25,7 +19,4 @@ }, | ||
}, | ||
validate: function validate(options) { | ||
validateNumber(options.increment, 'increment'); | ||
}, | ||
getNextInterval: function getNextInterval(options, attemptNumber, currentInterval) { | ||
return currentInterval + options.increment; | ||
getNextInterval: function getNextInterval(count, options) { | ||
return options.start + options.increment * count; | ||
} | ||
@@ -36,11 +27,11 @@ }, | ||
defaults: { | ||
min: 1000 | ||
min: 1000, | ||
max: 30000 | ||
}, | ||
validate: function validate(options) { | ||
validateNumber(options.min, 'min'); | ||
}, | ||
getNextInterval: function getNextInterval(options, attemptNumber, currentInterval) { | ||
return Math.max(Math.round(Math.random() * (Math.pow(2, attemptNumber) - min) * 1000), options.min); | ||
getNextInterval: function getNextInterval(count, options) { | ||
return Math.min(options.max, Math.round(Math.random() * (Math.pow(2, count) * 1000 - options.min) + options.min)); | ||
} | ||
} | ||
}; | ||
}; | ||
module.exports = strategies; |
@@ -9,2 +9,6 @@ 'use strict'; | ||
var _strategies = require('../lib/strategies'); | ||
var _strategies2 = _interopRequireDefault(_strategies); | ||
var _bluebird = require('bluebird'); | ||
@@ -179,2 +183,48 @@ | ||
}); | ||
describe('fixed interval strategy', function () { | ||
it('polls on a fixed interval', function () { | ||
var options = { | ||
interval: 1000 | ||
}; | ||
var expectedIntervals = [1000, 1000, 1000, 1000, 1000]; | ||
expectedIntervals.forEach(function (interval, index) { | ||
expect(_strategies2.default['fixed-interval'].getNextInterval(index, options)).toEqual(interval); | ||
}); | ||
}); | ||
}); | ||
describe('linear backoff strategy', function () { | ||
it('increases the interval linearly', function () { | ||
var options = { | ||
start: 1000, | ||
increment: 500 | ||
}; | ||
var expectedIntervals = [1000, 1500, 2000, 2500, 3000]; | ||
expectedIntervals.forEach(function (interval, index) { | ||
expect(_strategies2.default['linear-backoff'].getNextInterval(index, options)).toEqual(interval); | ||
}); | ||
}); | ||
}); | ||
describe('exponential backoff strategy', function () { | ||
it('uses exponential backoff with jitter', function () { | ||
var randoms = [0.2, 0.4, 0.6, 0.8, 0.9]; | ||
var expectedIntervals = [1000, 1400, 2800, 6600, 10000]; | ||
Math.random = function () { | ||
return randoms.shift(); | ||
}; | ||
var options = { | ||
min: 1000, | ||
max: 10000 | ||
}; | ||
expectedIntervals.forEach(function (interval, index) { | ||
expect(_strategies2.default['exponential-backoff'].getNextInterval(index, options)).toEqual(interval); | ||
}); | ||
}); | ||
}); | ||
}); |
{ | ||
"name": "promise-poller", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": "A basic poller built on top of promises", | ||
@@ -5,0 +5,0 @@ "main": "dist/lib/promise-poller.js", |
@@ -32,3 +32,3 @@ # promise-poller | ||
## Specify polling options | ||
You can specify a different polling interal or number of retries: | ||
You can specify a different polling interval or number of retries: | ||
@@ -41,2 +41,28 @@ var poller = promisePoller({ | ||
## Select polling strategy | ||
By default, `promise-poller` will use a fixed interval between each poll attempt. For example, with an `interval` option of 500, the poller will poll approximately every 500 milliseconds. This is the `fixed-interval` strategy. There are two other strategies available that may better suit your use case. To select a polling strategy, specify the `strategy` option, e.g.: | ||
promisePoller({ | ||
taskFn: myTask, | ||
strategy: 'linear-backoff' | ||
}); | ||
### Linear backoff (`linear-backoff`) | ||
Options: | ||
* `start` - The starting value to use for the polling interval (default = 1000) | ||
* `increment` - The amount to increase the interval by on each poll attempt. | ||
Linear backoff will increase the interval linearly by some constant amount for each poll attempt. For example, using the default options, the first retry will wait 1000 milliseconds. Each successive retry will wait an additional 1000 milliseconds: 1000, 2000, 3000, 4000, etc. | ||
### Exponential backoff with jitter (`exponential-backoff`) | ||
Options: | ||
* `min` - The minimum interval amount to use (default = 1000) | ||
* `max` - The maximum interval amount to use (default = 30000) | ||
Exponential backoff increases the poll interval by a power of two for each poll attempt. `promise-poller` uses exponential backoff with jitter. Jitter takes a random value between `min` and 2^*n* on the *n*th polling interval, not to exceed `max`. | ||
For more information about exponential backoff with jitter, and its advantages, see [https://www.awsarchitectureblog.com/2015/03/backoff.html](https://www.awsarchitectureblog.com/2015/03/backoff.html). | ||
## Progress notification | ||
@@ -43,0 +69,0 @@ You can also specify a progress callback function. Each time the task fails, the progress callback will be called with the number of retries remaining and the error that occurred (the value that the task promise was rejected with): |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19912
13
329
124