Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dapi/AutoRetry.js74
-rw-r--r--test/dapi/AutoRetryTest.js28
2 files changed, 44 insertions, 58 deletions
diff --git a/src/dapi/AutoRetry.js b/src/dapi/AutoRetry.js
index 77048c0..810677c 100644
--- a/src/dapi/AutoRetry.js
+++ b/src/dapi/AutoRetry.js
@@ -23,6 +23,14 @@ var Trait = require( 'easejs' ).Trait,
DataApi = require( './DataApi' );
+/**
+ * Automatically retries requests while satisfying a given predicate
+ *
+ * It is important to distinguish between the concept of a request failure
+ * and a retry predicate: the former represents a problem with the request,
+ * whereas the latter indicates that a retry should be performed, but may
+ * not necessarily imply a request failure.
+ */
module.exports = Trait( 'AutoRetry' )
.implement( DataApi )
.extend(
@@ -51,9 +59,9 @@ module.exports = Trait( 'AutoRetry' )
/**
* Initialize auto-retry
*
- * If TRIES is negative, then requests will continue indefinitely until
- * one succeeds or is aborted by DELAY. If TRIES is 0, then no requests
- * will be performed.
+ * If TRIES is negative, then requests will continue indefinitely while
+ * the retry predicate is true, or is aborted by DELAY. If TRIES is 0,
+ * then no requests will be performed.
*
* If DELAY is a function, then it invoked with a retry continuation
* before each retry, the number of tries remaining, and a failure
@@ -87,7 +95,7 @@ module.exports = Trait( 'AutoRetry' )
this._pred = pred;
this._tries = +tries;
- this._delay = delay || function( _, c ) { c(); };
+ this._delay = delay || function( _, c, __ ) { c(); };
},
@@ -100,13 +108,13 @@ module.exports = Trait( 'AutoRetry' )
* necessarily asynchronously---that remains undefined).
*
* Otherwise, requests will continue to be re-issued until either the
- * request succeeds or the number of retries are exhausted, whichever
- * comes first. Once the retries are exhausted, the error and output
- * data from the final request are returned.
+ * retry predicate fails or the number of retries are exhausted,
+ * whichever comes first. Once the retries are exhausted, the error and
+ * output data from the final request are returned.
*
* If the number of tries is negative, then requests will be performed
- * indefinitely until success; the delay function (as provided via the
- * constructor) may be used to abort in this case.
+ * indefinitely while the retry predicate is met; the delay function (as
+ * provided via the constructor) may be used to abort in this case.
*
* @param {string} input binary data to transmit
* @param {function(?Error,*)} callback continuation upon reply
@@ -122,7 +130,8 @@ module.exports = Trait( 'AutoRetry' )
/**
- * Recursively perform request until success or try exhaustion
+ * Recursively perform request until retry predicate failure or try
+ * count exhaustion
*
* For more information, see `#request'.
*
@@ -146,22 +155,22 @@ module.exports = Trait( 'AutoRetry' )
this.request.super.call( this, input, function( err, output )
{
+ var complete = function()
+ {
+ callback( err, output );
+ };
+
// predicate determines whether a retry is necessary
if ( !!_self._pred( err, output ) === false )
{
- return _self._succeed( output, callback );
+ return complete();
}
- var fail = function()
- {
- _self._fail( err, output, callback );
- };
-
// note that we intentionally do not want to check <= 1, so that
// we can proceed indefinitely (JavaScript does not wrap on overflow)
if ( n === 1 )
{
- return fail();
+ return complete();
}
_self._delay(
@@ -170,37 +179,8 @@ module.exports = Trait( 'AutoRetry' )
{
_self._try( input, callback, ( n - 1 ) );
},
- fail
+ complete
);
} );
},
-
-
- /**
- * Produce a successful response
- *
- * @param {*} output output data
- * @param {function(?Error,*)} callback continuation to invoke
- *
- * @return {undefined}
- */
- 'private _succeed': function( output, callback )
- {
- callback( null, output );
- },
-
-
- /**
- * Produce a negative response
- *
- * @param {Error} err most recent error
- * @param {*} output most recent output data
- * @param {function(?Error,*)} callback continuation to invoke
- *
- * @return {undefined}
- */
- 'private _fail': function( err, output, callback )
- {
- callback( err, output );
- },
} );
diff --git a/test/dapi/AutoRetryTest.js b/test/dapi/AutoRetryTest.js
index 8b10529..b9c6867 100644
--- a/test/dapi/AutoRetryTest.js
+++ b/test/dapi/AutoRetryTest.js
@@ -32,9 +32,9 @@ var _void = function() {},
describe( 'dapi.AutoRetry trait', function()
{
/**
- * If there are no failures, then AutoRetry has no observable effects.
+ * If there are no retries, then AutoRetry has no observable effects.
*/
- describe( 'when the request is successful', function()
+ describe( 'when the request does not need retrying', function()
{
it( 'makes only one request', function( done )
{
@@ -55,19 +55,25 @@ describe( 'dapi.AutoRetry trait', function()
} );
- it( 'returns the response data with no error', function( done )
+ /**
+ * We expect that any error will be proxied back to us; this is an
+ * important concept, since it allow separating the idea of a
+ * "retry" from that of a "failure": the latter represents a problem
+ * with the request, whereas the former indicates that a request
+ * should be performed once again.
+ */
+ it( 'returns the response data, including any error', function( done )
{
- var chk = { foo: 'bar' };
+ var chk = { foo: 'bar' },
+ chk_err = Error( 'foo' );
- // notice that we provide an error to the stub; this will ensure
- // that the returned error is null even when one is provided
- var stub = _createStub( {}, chk )
+ var stub = _createStub( chk_err, chk )
.use( Sut( _void, 1 ) )
();
stub.request( '', function( err, data )
{
- expect( err ).to.equal( null );
+ expect( err ).to.equal( chk_err );
expect( data ).to.equal( chk );
done();
} );
@@ -78,9 +84,9 @@ describe( 'dapi.AutoRetry trait', function()
/**
* This is when we care.
*/
- describe( 'when the request fails', function()
+ describe( 'when the retry predicate is true', function()
{
- it( 'will re-perform request N-1 times until failure', function( done )
+ it( 'will re-perform request N-1 times until false', function( done )
{
var n = 5;
@@ -207,7 +213,7 @@ describe( 'dapi.AutoRetry trait', function()
} );
- it( 'will call delay function until success', function()
+ it( 'will call delay function until predicate falsity', function()
{
var n = 5;
var wait = function( tries_left, c )