Comparing version
@@ -7,4 +7,6 @@ function RetryOperation(timeouts, options) { | ||
this._originalTimeouts = JSON.parse(JSON.stringify(timeouts)); | ||
this._timeouts = timeouts; | ||
this._options = options || {}; | ||
this._maxRetryTime = options && options.maxRetryTime || Infinity; | ||
this._fn = null; | ||
@@ -16,2 +18,3 @@ this._errors = []; | ||
this._timeout = null; | ||
this._operationStart = null; | ||
@@ -24,2 +27,7 @@ if (this._options.forever) { | ||
RetryOperation.prototype.reset = function() { | ||
this._attempts = 1; | ||
this._timeouts = this._originalTimeouts; | ||
} | ||
RetryOperation.prototype.stop = function() { | ||
@@ -42,2 +50,7 @@ if (this._timeout) { | ||
} | ||
var currentTime = new Date().getTime(); | ||
if (err && currentTime - this._operationStart >= this._maxRetryTime) { | ||
this._errors.unshift(new Error('RetryOperation timeout occurred')); | ||
return false; | ||
} | ||
@@ -67,3 +80,3 @@ this._errors.push(err); | ||
if (this._options.unref) { | ||
if (self._options.unref) { | ||
self._timeout.unref(); | ||
@@ -102,2 +115,4 @@ } | ||
this._operationStart = new Date().getTime(); | ||
this._fn(this._attempts); | ||
@@ -104,0 +119,0 @@ }; |
@@ -7,3 +7,4 @@ var RetryOperation = require('./retry_operation'); | ||
forever: options && options.forever, | ||
unref: options && options.unref | ||
unref: options && options.unref, | ||
maxRetryTime: options && options.maxRetryTime | ||
}); | ||
@@ -79,5 +80,5 @@ }; | ||
obj[method] = function retryWrapper() { | ||
obj[method] = function retryWrapper(original) { | ||
var op = exports.operation(options); | ||
var args = Array.prototype.slice.call(arguments); | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
var callback = args.pop(); | ||
@@ -98,5 +99,5 @@ | ||
}); | ||
}; | ||
}.bind(obj, original); | ||
obj[method].options = options; | ||
} | ||
}; |
@@ -6,3 +6,3 @@ { | ||
"license": "MIT", | ||
"version": "0.10.1", | ||
"version": "0.12.0", | ||
"homepage": "https://github.com/tim-kos/node-retry", | ||
@@ -18,3 +18,3 @@ "repository": { | ||
"engines": { | ||
"node": "*" | ||
"node": ">= 4" | ||
}, | ||
@@ -24,4 +24,12 @@ "dependencies": {}, | ||
"fake": "0.2.0", | ||
"far": "0.0.1" | ||
"istanbul": "^0.4.5", | ||
"tape": "^4.8.0" | ||
}, | ||
"scripts": { | ||
"test": "./node_modules/.bin/istanbul cover ./node_modules/tape/bin/tape ./test/integration/*.js", | ||
"release:major": "env SEMANTIC=major npm run release", | ||
"release:minor": "env SEMANTIC=minor npm run release", | ||
"release:patch": "env SEMANTIC=patch npm run release", | ||
"release": "npm version ${SEMANTIC:-patch} -m \"Release %s\" && git push && git push --tags && npm publish" | ||
} | ||
} |
@@ -0,1 +1,6 @@ | ||
<!-- badges/ --> | ||
[](http://travis-ci.org/tim-kos/node-retry "Check this project's build status on TravisCI") | ||
[](https://codecov.io/gh/tim-kos/node-retry) | ||
<!-- /badges --> | ||
# retry | ||
@@ -63,3 +68,4 @@ | ||
* `forever`: Whether to retry forever, defaults to `false`. | ||
* `unref`: Wether to [unref](https://nodejs.org/api/timers.html#timers_unref) the setTimeout's, defaults to `false`. | ||
* `unref`: Whether to [unref](https://nodejs.org/api/timers.html#timers_unref) the setTimeout's, defaults to `false`. | ||
* `maxRetryTime`: The maximum time (in milliseconds) that the retried operation is allowed to run. Default is `Infinity`. | ||
@@ -73,3 +79,3 @@ ### retry.timeouts([options]) | ||
* `retries`: The maximum amount of times to retry the operation. Default is `10`. | ||
* `retries`: The maximum amount of times to retry the operation. Default is `10`. Seting this to `1` means `do it once, then retry it once`. | ||
* `factor`: The exponential factor to use. Default is `2`. | ||
@@ -148,4 +154,6 @@ * `minTimeout`: The number of milliseconds before starting the first retry. Default is `1000`. | ||
Returns an array of all errors that have been passed to | ||
`retryOperation.retry()` so far. | ||
Returns an array of all errors that have been passed to `retryOperation.retry()` so far. The | ||
returning array has the errors ordered chronologically based on when they were passed to | ||
`retryOperation.retry()`, which means the first passed error is at index zero and the last is | ||
at the last index. | ||
@@ -191,2 +199,6 @@ #### retryOperation.mainError() | ||
#### retryOperation.reset() | ||
Resets the internal state of the operation object, so that you can call `attempt()` again as if this was a new operation object. | ||
#### retryOperation.attempts() | ||
@@ -193,0 +205,0 @@ |
@@ -6,2 +6,41 @@ var common = require('../common'); | ||
(function testReset() { | ||
var error = new Error('some error'); | ||
var operation = retry.operation([1, 2, 3]); | ||
var attempts = 0; | ||
var finalCallback = fake.callback('finalCallback'); | ||
fake.expectAnytime(finalCallback); | ||
var expectedFinishes = 1; | ||
var finishes = 0; | ||
var fn = function() { | ||
operation.attempt(function(currentAttempt) { | ||
attempts++; | ||
assert.equal(currentAttempt, attempts); | ||
if (operation.retry(error)) { | ||
return; | ||
} | ||
finishes++ | ||
assert.equal(expectedFinishes, finishes); | ||
assert.strictEqual(attempts, 4); | ||
assert.strictEqual(operation.attempts(), attempts); | ||
assert.strictEqual(operation.mainError(), error); | ||
if (finishes < 2) { | ||
attempts = 0; | ||
expectedFinishes++; | ||
operation.reset(); | ||
fn() | ||
} else { | ||
finalCallback(); | ||
} | ||
}); | ||
}; | ||
fn(); | ||
})(); | ||
(function testErrors() { | ||
@@ -57,3 +96,2 @@ var operation = retry.operation(); | ||
(function testRetry() { | ||
var times = 3; | ||
var error = new Error('some error'); | ||
@@ -137,3 +175,3 @@ var operation = retry.operation([1, 2, 3]); | ||
var maxTime = minTime + 20 // add a little headroom for code execution time | ||
assert(endTime > minTime) | ||
assert(endTime >= minTime) | ||
assert(endTime < maxTime) | ||
@@ -180,1 +218,45 @@ assert.strictEqual(attempts, 4); | ||
})(); | ||
(function testMaxRetryTime() { | ||
var error = new Error('some error'); | ||
var maxRetryTime = 30; | ||
var operation = retry.operation({ | ||
minTimeout: 1, | ||
maxRetryTime: maxRetryTime | ||
}); | ||
var attempts = 0; | ||
var finalCallback = fake.callback('finalCallback'); | ||
fake.expectAnytime(finalCallback); | ||
var longAsyncFunction = function (wait, callback){ | ||
setTimeout(callback, wait); | ||
}; | ||
var fn = function() { | ||
var startTime = new Date().getTime(); | ||
operation.attempt(function(currentAttempt) { | ||
attempts++; | ||
assert.equal(currentAttempt, attempts); | ||
if (attempts !== 2) { | ||
if (operation.retry(error)) { | ||
return; | ||
} | ||
} else { | ||
var curTime = new Date().getTime(); | ||
longAsyncFunction(maxRetryTime - (curTime - startTime - 1), function(){ | ||
if (operation.retry(error)) { | ||
assert.fail('timeout should be occurred'); | ||
return; | ||
} | ||
assert.strictEqual(operation.mainError(), error); | ||
finalCallback(); | ||
}); | ||
} | ||
}); | ||
}; | ||
fn(); | ||
})(); |
@@ -17,5 +17,5 @@ var common = require('../common'); | ||
retry.wrap(lib); | ||
assert.equal(lib.fn1.name, 'retryWrapper'); | ||
assert.equal(lib.fn2.name, 'retryWrapper'); | ||
assert.equal(lib.fn3.name, 'retryWrapper'); | ||
assert.equal(lib.fn1.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn2.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn3.name, 'bound retryWrapper'); | ||
}()); | ||
@@ -26,5 +26,5 @@ | ||
retry.wrap(lib, {retries: 2}); | ||
assert.equal(lib.fn1.name, 'retryWrapper'); | ||
assert.equal(lib.fn2.name, 'retryWrapper'); | ||
assert.equal(lib.fn3.name, 'retryWrapper'); | ||
assert.equal(lib.fn1.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn2.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn3.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn1.options.retries, 2); | ||
@@ -38,5 +38,5 @@ assert.equal(lib.fn2.options.retries, 2); | ||
retry.wrap(lib, ['fn2', 'fn3']); | ||
assert.notEqual(lib.fn1.name, 'retryWrapper'); | ||
assert.equal(lib.fn2.name, 'retryWrapper'); | ||
assert.equal(lib.fn3.name, 'retryWrapper'); | ||
assert.notEqual(lib.fn1.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn2.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn3.name, 'bound retryWrapper'); | ||
}()); | ||
@@ -47,5 +47,5 @@ | ||
retry.wrap(lib, {retries: 2}, ['fn2', 'fn3']); | ||
assert.notEqual(lib.fn1.name, 'retryWrapper'); | ||
assert.equal(lib.fn2.name, 'retryWrapper'); | ||
assert.equal(lib.fn3.name, 'retryWrapper'); | ||
assert.notEqual(lib.fn1.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn2.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn3.name, 'bound retryWrapper'); | ||
assert.equal(lib.fn2.options.retries, 2); | ||
@@ -70,2 +70,26 @@ assert.equal(lib.fn3.options.retries, 2); | ||
(function runWrappedSeveralWithoutError() { | ||
var callbacksCalled = 0; | ||
var lib = { | ||
fn1: function (a, callback) { | ||
assert.equal(a, 1); | ||
assert.equal(typeof callback, 'function'); | ||
callback(); | ||
}, | ||
fn2: function (a, callback) { | ||
assert.equal(a, 2); | ||
assert.equal(typeof callback, 'function'); | ||
callback(); | ||
} | ||
}; | ||
retry.wrap(lib, {}, ['fn1', 'fn2']); | ||
lib.fn1(1, function() { | ||
callbacksCalled++; | ||
}); | ||
lib.fn2(2, function() { | ||
callbacksCalled++; | ||
}); | ||
assert.equal(callbacksCalled, 2); | ||
}()); | ||
(function runWrappedWithError() { | ||
@@ -72,0 +96,0 @@ var callbackCalled; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
32210
17.37%656
18.2%228
5.56%3
50%