[Pkg-javascript-commits] [node-async] 417/480: implement async.retry using async.series

Jonas Smedegaard js at moszumanska.debian.org
Fri May 2 08:58:48 UTC 2014


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository node-async.

commit 04df2a7eca7e0ddaafe9b866753a6352ef567872
Author: Jesse Houchins <jesse.houchins at tstmedia.com>
Date:   Fri Mar 28 22:37:01 2014 -0500

    implement async.retry using async.series
---
 README.md          | 42 ++++++++++++++++++++++++++++++++++++++++++
 lib/async.js       | 27 +++++++++++++++++++++++++++
 test/test-async.js | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/README.md b/README.md
index acee1b2..278c315 100644
--- a/README.md
+++ b/README.md
@@ -146,6 +146,7 @@ Usage:
 * [`queue`](#queue)
 * [`cargo`](#cargo)
 * [`auto`](#auto)
+* [`retry`](#retry)
 * [`iterator`](#iterator)
 * [`apply`](#apply)
 * [`nextTick`](#nextTick)
@@ -1325,6 +1326,47 @@ new tasks much easier (and the code more readable).
 
 ---------------------------------------
 
+<a name="retry" />
+### retry([times = 5], task, [callback])
+
+Attempts to get a successful response from `task` no more than `times` times before
+returning an error. If the task is successful, the `callback` will be passed the result
+of the successfull task. If all attemps fail, the callback will be passed the error and
+result (if any) of the final attempt.
+
+__Arguments__
+
+* `task(callback, results)` - A function which receives two arguments: (1) a `callback(err, result)`
+  which must be called when finished, passing `err` (which can be `null`) and the `result` of 
+  the function's execution, and (2) a `results` object, containing the results of
+  the previously executed functions (if nested inside another controll flow).
+* `callback(err, results)` - An optional callback which is called when the
+  task has succeeded, or after the final failed attempt. It receives the `err` and `result` arguments of the last attempt at completing the `task`.
+
+The [`retry`](#retry) function can be used as a stand-alone controll flow by passing a
+callback, as shown below:
+
+```js
+async.retry(3, apiMethod, function(err, result) {
+    // do something with the result
+});
+```
+
+It can also be embeded within other controll flow functions to retry individual methods
+that are not as reliable, like this:
+
+```js
+async.auto({
+    users: api.getUsers.bind(api),
+    payments: async.retry(3, api.getPayments.bind(api))
+}, function(err, results) {
+  // do something with the results
+});
+```
+
+
+---------------------------------------
+
 <a name="iterator" />
 ### iterator(tasks)
 
diff --git a/lib/async.js b/lib/async.js
index 42b2621..92c684a 100755
--- a/lib/async.js
+++ b/lib/async.js
@@ -481,6 +481,33 @@
         });
     };
 
+    async.retry = function(times, task, callback) {
+        var DEFAULT_TIMES = 5;
+        var attempts = [];
+        // Use defaults if times not passed
+        if (typeof times === 'function') {
+            callback = task;
+            task = times;
+            times = DEFAULT_TIMES;
+        }
+        // Make sure times is a number
+        times = parseInt(times, 10) || DEFAULT_TIMES;
+        var retryAttempt = function(task, finalAttempt) {
+            return function(seriesCallback, results) {
+                task(function(err, result){
+                    seriesCallback(!err || finalAttempt, {err: err, result: result});
+                }, results);
+            };
+        };
+        while (times) {
+            attempts.push(retryAttempt(task, !(times-=1)));
+        }
+        async.series(attempts, function(done, data){
+            data = data[data.length - 1];
+            callback(data.err, data.result);
+        });
+    };
+
     async.waterfall = function (tasks, callback) {
         callback = callback || function () {};
         if (!_isArray(tasks)) {
diff --git a/test/test-async.js b/test/test-async.js
index 32a6cba..7095af5 100755
--- a/test/test-async.js
+++ b/test/test-async.js
@@ -579,6 +579,41 @@ exports['auto modifying results causes final callback to run early'] = function(
     });
 };
 
+// Issue 306 on github: https://github.com/caolan/async/issues/306
+exports['retry when attempt succeeds'] = function(test) {
+    var failed = 3
+    var callCount = 0
+    var expectedResult = 'success'
+    function fn(callback, results) {
+        callCount++
+        failed--
+        if (!failed) callback(null, expectedResult)
+        else callback(true) // respond with error
+    }
+    async.retry(fn, function(err, result){
+        test.equal(callCount, 3, 'did not retry the correct number of times')
+        test.equal(result, expectedResult, 'did not return the expected result')
+        test.done();
+    });
+};
+
+exports['retry when all attempts succeeds'] = function(test) {
+    var times = 3;
+    var callCount = 0;
+    var error = 'ERROR';
+    var erroredResult = 'RESULT';
+    function fn(callback, results) {
+        callCount++;
+        callback(error + callCount, erroredResult + callCount); // respond with indexed values
+    };
+    async.retry(times, fn, function(err, result){
+        test.equal(callCount, 3, "did not retry the correct number of times");
+        test.equal(err, error + times, "Incorrect error was returned");
+        test.equal(result, erroredResult + times, "Incorrect result was returned");
+        test.done();
+    });
+};
+
 exports['waterfall'] = function(test){
     test.expect(6);
     var call_order = [];

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-async.git



More information about the Pkg-javascript-commits mailing list