From cbc5b4f864f621fe6068a6455faca2c06418c90f Mon Sep 17 00:00:00 2001 From: Bojan Djurkovic Date: Tue, 2 Aug 2016 12:55:26 -0300 Subject: add filter option to retry() and retryable() to allow for error filtering and control of retry flow. Resolves #1256. --- lib/retry.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/retry.js b/lib/retry.js index 8163ad9..a700516 100644 --- a/lib/retry.js +++ b/lib/retry.js @@ -19,6 +19,10 @@ import constant from 'lodash/constant'; * * `interval` - The time to wait between retries, in milliseconds. The * default is `0`. The interval may also be specified as a function of the * retry count (see example). + * * `filter` - Synchronous function that is invoked on erroneous result with the + * the error. If it returns `true` the retry attempts will continue, if the + * function returns `false` the retry flow is aborting with the current + * attempt's error and result being returned to the final callback. * * If `opts` is a number, the number specifies the number of times to retry, * with the default interval of `0`. * @param {Function} task - A function which receives two arguments: (1) a @@ -62,6 +66,16 @@ import constant from 'lodash/constant'; * // do something with the result * }); * + * // try calling apiMethod only when error condition satisfies, all other + * // errors will abort the retry control flow and return to final callback + * async.retry({ + * filter: function(err) { + * return err.message === 'Temporary error'; // only retry on a specific error + * } + * }, apiMethod, function(err, result) { + * // do something with the result + * }); + * * // It can also be embedded within other control flow functions to retry * // individual methods that are not as reliable, like this: * async.auto({ @@ -70,6 +84,7 @@ import constant from 'lodash/constant'; * }, function(err, results) { * // do something with the results * }); + * */ export default function retry(opts, task, callback) { var DEFAULT_TIMES = 5; @@ -87,6 +102,10 @@ export default function retry(opts, task, callback) { acc.intervalFunc = typeof t.interval === 'function' ? t.interval : constant(+t.interval || DEFAULT_INTERVAL); + + if(typeof t.filter === 'function') { + acc.filter = t.filter; + } } else if (typeof t === 'number' || typeof t === 'string') { acc.times = +t || DEFAULT_TIMES; } else { @@ -94,7 +113,6 @@ export default function retry(opts, task, callback) { } } - if (arguments.length < 3 && typeof opts === 'function') { callback = task || noop; task = opts; @@ -111,7 +129,16 @@ export default function retry(opts, task, callback) { function retryAttempt() { task(function(err) { if (err && attempt++ < options.times) { - setTimeout(retryAttempt, options.intervalFunc(attempt)); + var proceed = true; + if(options.filter) { + proceed = options.filter(err); + } + + if(proceed) { + setTimeout(retryAttempt, options.intervalFunc(attempt)); + } else { + callback.apply(null, arguments); + } } else { callback.apply(null, arguments); } -- cgit v1.2.1 From 0337ee0b2e582917cc15e6efc186e3c89e0a2cdb Mon Sep 17 00:00:00 2001 From: Bojan Djurkovic Date: Wed, 3 Aug 2016 19:46:51 -0300 Subject: changed the error test function to continueOperation. improved comment documentation and fixed code based on PR feedback. --- lib/retry.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/retry.js b/lib/retry.js index a700516..d8b711b 100644 --- a/lib/retry.js +++ b/lib/retry.js @@ -19,10 +19,11 @@ import constant from 'lodash/constant'; * * `interval` - The time to wait between retries, in milliseconds. The * default is `0`. The interval may also be specified as a function of the * retry count (see example). - * * `filter` - Synchronous function that is invoked on erroneous result with the - * the error. If it returns `true` the retry attempts will continue, if the - * function returns `false` the retry flow is aborting with the current - * attempt's error and result being returned to the final callback. + * * `continueOperation` - An optional synchronous function that is invoked on + * erroneous result with the the error. If it returns `true` the retry attempts + * will continue, if the function returns `false` the retry flow is aborted + * with the current attempt's error and result being returned to the final + * callback. Invoked with (err). * * If `opts` is a number, the number specifies the number of times to retry, * with the default interval of `0`. * @param {Function} task - A function which receives two arguments: (1) a @@ -69,7 +70,7 @@ import constant from 'lodash/constant'; * // try calling apiMethod only when error condition satisfies, all other * // errors will abort the retry control flow and return to final callback * async.retry({ - * filter: function(err) { + * continueOperation: function(err) { * return err.message === 'Temporary error'; // only retry on a specific error * } * }, apiMethod, function(err, result) { @@ -103,9 +104,7 @@ export default function retry(opts, task, callback) { t.interval : constant(+t.interval || DEFAULT_INTERVAL); - if(typeof t.filter === 'function') { - acc.filter = t.filter; - } + acc.continueOperation = t.continueOperation; } else if (typeof t === 'number' || typeof t === 'string') { acc.times = +t || DEFAULT_TIMES; } else { @@ -129,11 +128,8 @@ export default function retry(opts, task, callback) { function retryAttempt() { task(function(err) { if (err && attempt++ < options.times) { - var proceed = true; - if(options.filter) { - proceed = options.filter(err); - } - + var proceed = typeof options.continueOperation != 'function' || + options.continueOperation(err); if(proceed) { setTimeout(retryAttempt, options.intervalFunc(attempt)); } else { -- cgit v1.2.1 From 0af976cc89096ee64db3bd08fe65e2b3445f56d5 Mon Sep 17 00:00:00 2001 From: Bojan Djurkovic Date: Thu, 4 Aug 2016 21:00:56 -0300 Subject: rename the new retry option to errorFilter and consolidate retry attempt condition into one statement --- lib/retry.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/retry.js b/lib/retry.js index d8b711b..45b09a8 100644 --- a/lib/retry.js +++ b/lib/retry.js @@ -19,11 +19,11 @@ import constant from 'lodash/constant'; * * `interval` - The time to wait between retries, in milliseconds. The * default is `0`. The interval may also be specified as a function of the * retry count (see example). - * * `continueOperation` - An optional synchronous function that is invoked on - * erroneous result with the the error. If it returns `true` the retry attempts - * will continue, if the function returns `false` the retry flow is aborted - * with the current attempt's error and result being returned to the final - * callback. Invoked with (err). + * * `errorFilter` - An optional synchronous function that is invoked on + * erroneous result. If it returns `true` the retry attempts will continue; + * if the function returns `false` the retry flow is aborted with the current + * attempt's error and result being returned to the final callback. + * Invoked with (err, result). * * If `opts` is a number, the number specifies the number of times to retry, * with the default interval of `0`. * @param {Function} task - A function which receives two arguments: (1) a @@ -70,7 +70,7 @@ import constant from 'lodash/constant'; * // try calling apiMethod only when error condition satisfies, all other * // errors will abort the retry control flow and return to final callback * async.retry({ - * continueOperation: function(err) { + * errorFilter: function(err) { * return err.message === 'Temporary error'; // only retry on a specific error * } * }, apiMethod, function(err, result) { @@ -104,7 +104,7 @@ export default function retry(opts, task, callback) { t.interval : constant(+t.interval || DEFAULT_INTERVAL); - acc.continueOperation = t.continueOperation; + acc.errorFilter = t.errorFilter; } else if (typeof t === 'number' || typeof t === 'string') { acc.times = +t || DEFAULT_TIMES; } else { @@ -127,14 +127,10 @@ export default function retry(opts, task, callback) { var attempt = 1; function retryAttempt() { task(function(err) { - if (err && attempt++ < options.times) { - var proceed = typeof options.continueOperation != 'function' || - options.continueOperation(err); - if(proceed) { - setTimeout(retryAttempt, options.intervalFunc(attempt)); - } else { - callback.apply(null, arguments); - } + if (err && attempt++ < options.times && + (typeof options.errorFilter != 'function' || + options.errorFilter(err))) { + setTimeout(retryAttempt, options.intervalFunc(attempt)); } else { callback.apply(null, arguments); } -- cgit v1.2.1 From 4367751bc420f4f279d83e8eae291708bf7990f6 Mon Sep 17 00:00:00 2001 From: Bojan Djurkovic Date: Mon, 8 Aug 2016 08:58:49 -0300 Subject: fix errorFilter comment to reflect that we only pass err argument. Removed setTimeout from retryable tests --- lib/retry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/retry.js b/lib/retry.js index 45b09a8..a5ad866 100644 --- a/lib/retry.js +++ b/lib/retry.js @@ -23,7 +23,7 @@ import constant from 'lodash/constant'; * erroneous result. If it returns `true` the retry attempts will continue; * if the function returns `false` the retry flow is aborted with the current * attempt's error and result being returned to the final callback. - * Invoked with (err, result). + * Invoked with (err). * * If `opts` is a number, the number specifies the number of times to retry, * with the default interval of `0`. * @param {Function} task - A function which receives two arguments: (1) a -- cgit v1.2.1