diff options
-rw-r--r-- | README.md | 26 | ||||
-rw-r--r-- | lib/index.js | 3 | ||||
-rw-r--r-- | lib/retryable.js | 20 | ||||
-rw-r--r-- | mocha_test/retryable.js | 64 | ||||
-rwxr-xr-x | test/test-async.js | 42 |
5 files changed, 113 insertions, 42 deletions
@@ -221,6 +221,7 @@ Some functions are also available in the following forms: * [`auto`](#auto) * [`autoInject`](#autoInject) * [`retry`](#retry) +* [`retryable`](#retryable) * [`iterator`](#iterator) * [`times`](#times), `timesSeries`, `timesLimit` * [`race`](#race) @@ -1580,6 +1581,31 @@ async.auto({ }); ``` + +--------------------------------------- + +<a name="retryable"></a> + +### retryable([opts = {times: 5, interval: 0}| 5], task) + +A close relative of `retry`. This method wraps a task and makes it retryable, rather than immediately calling it with retries. + +__Arguments__ + +* `opts` - optional options, exactly the same as from `retry` +* `task` - the asynchronous function to wrap + +__Example__ + +```js +async.auto({ + dep1: async.retryable(3, getFromFlakyService), + process: ["dep1", async.retryable(3, function (results, cb) { + maybeProcessData(results.dep1, cb) + })] +}, callback) +``` + --------------------------------------- <a name="iterator"></a> diff --git a/lib/index.js b/lib/index.js index de337a2..e3eb48d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -51,6 +51,7 @@ import reject from './reject'; import rejectLimit from './rejectLimit'; import rejectSeries from './rejectSeries'; import retry from './retry'; +import retryable from './retryable'; import seq from './seq'; import series from './series'; import setImmediate from './setImmediate'; @@ -120,6 +121,7 @@ export default { rejectLimit: rejectLimit, rejectSeries: rejectSeries, retry: retry, + retryable: retryable, seq: seq, series: series, setImmediate: setImmediate, @@ -207,6 +209,7 @@ export { rejectLimit as rejectLimit, rejectSeries as rejectSeries, retry as retry, + retryable as retryable, seq as seq, series as series, setImmediate as setImmediate, diff --git a/lib/retryable.js b/lib/retryable.js new file mode 100644 index 0000000..26fa609 --- /dev/null +++ b/lib/retryable.js @@ -0,0 +1,20 @@ +import retry from './retry'; +import rest from 'lodash/rest'; + +export default function (opts, task) { + if (!task) { + task = opts; + opts = null; + } + return rest(function (args) { + var callback = args.pop(); + + function taskFn(cb) { + task.apply(null, args.concat([cb])); + } + + if (opts) retry(opts, taskFn, callback); + else retry(taskFn, callback); + + }); +} diff --git a/mocha_test/retryable.js b/mocha_test/retryable.js new file mode 100644 index 0000000..8141629 --- /dev/null +++ b/mocha_test/retryable.js @@ -0,0 +1,64 @@ +var async = require('../lib'); +var expect = require('chai').expect; +var assert = require('assert'); + +describe('retryable', function () { + it('basics', function (done) { + var calls = 0; + var retryableTask = async.retryable(3, function (arg, cb) { + calls++; + expect(arg).to.equal(42); + cb('fail'); + }); + + retryableTask(42, function (err) { + expect(err).to.equal('fail'); + expect(calls).to.equal(3); + done(); + }); + + setTimeout(function () { + }, 15); + }); + + it('should work as an embedded task', function(done) { + var retryResult = 'RETRY'; + var fooResults; + var retryResults; + + async.auto({ + dep: async.constant('dep'), + foo: ['dep', function(results, callback){ + fooResults = results; + callback(null, 'FOO'); + }], + retry: ['dep', async.retryable(function(results, callback) { + retryResults = results; + callback(null, retryResult); + })] + }, function(err, results){ + assert.equal(results.retry, retryResult, "Incorrect result was returned from retry function"); + assert.equal(fooResults, retryResults, "Incorrect results were passed to retry function"); + done(); + }); + }); + + it('should work as an embedded task with interval', function(done) { + var start = new Date().getTime(); + var opts = {times: 5, interval: 100}; + + async.auto({ + foo: function(callback){ + callback(null, 'FOO'); + }, + retry: async.retryable(opts, function(callback) { + callback('err'); + }) + }, function(){ + var duration = new Date().getTime() - start; + var expectedMinimumDuration = (opts.times -1) * opts.interval; + assert(duration >= expectedMinimumDuration, "The duration should have been greater than " + expectedMinimumDuration + ", but was " + duration); + done(); + }); + }); +}); diff --git a/test/test-async.js b/test/test-async.js index 9f86acc..171810c 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -278,48 +278,6 @@ exports['seq without callback'] = function (test) { add2mul3.call(testcontext, 3); }; -// need to fix retry, this isn't working -/* -exports['retry as an embedded task'] = function(test) { - var retryResult = 'RETRY'; - var fooResults; - var retryResults; - - async.auto({ - dep: async.constant('dep'), - foo: ['dep', function(results, callback){ - fooResults = results; - callback(null, 'FOO'); - }], - retry: ['dep', async.retry(function(results, callback) { - retryResults = results; - callback(null, retryResult); - })] - }, function(err, results){ - test.equal(results.retry, retryResult, "Incorrect result was returned from retry function"); - test.equal(fooResults, retryResults, "Incorrect results were passed to retry function"); - test.done(); - }); -}; - -exports['retry as an embedded task with interval'] = function(test) { - var start = new Date().getTime(); - var opts = {times: 5, interval: 100}; - - async.auto({ - foo: function(callback){ - callback(null, 'FOO'); - }, - retry: async.retry(opts, function(callback) { - callback('err'); - }) - }, function(){ - var duration = new Date().getTime() - start; - var expectedMinimumDuration = (opts.times -1) * opts.interval; - test.ok(duration >= expectedMinimumDuration, "The duration should have been greater than " + expectedMinimumDuration + ", but was " + duration); - test.done(); - }); -};*/ exports['parallel'] = function(test){ var call_order = []; |