summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Early <alexander.early@gmail.com>2016-03-18 15:46:28 -0700
committerAlex Early <alexander.early@gmail.com>2016-03-18 15:46:28 -0700
commitbdf4a96113d93f005c8fc488f42ecfb884f48fce (patch)
treebb828869988a37cb7d4f1eb90a366b6540303d94
parent902eec8ec2911cdd787477382b0b07123afe7d2b (diff)
parent7980923b12ee288243bc922525f70b07c3a41872 (diff)
downloadasync-bdf4a96113d93f005c8fc488f42ecfb884f48fce.tar.gz
Merge pull request #1058 from caolan/retryable
added retryable wrapper for async tasks
-rw-r--r--README.md26
-rw-r--r--lib/index.js3
-rw-r--r--lib/retryable.js20
-rw-r--r--mocha_test/retryable.js64
-rwxr-xr-xtest/test-async.js42
5 files changed, 113 insertions, 42 deletions
diff --git a/README.md b/README.md
index 1ce2fd2..5c932d1 100644
--- a/README.md
+++ b/README.md
@@ -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 = [];