You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
3.6 KiB
158 lines
3.6 KiB
function RetryOperation(timeouts, options) { |
|
// Compatibility for the old (timeouts, retryForever) signature |
|
if (typeof options === 'boolean') { |
|
options = { forever: options }; |
|
} |
|
|
|
this._originalTimeouts = JSON.parse(JSON.stringify(timeouts)); |
|
this._timeouts = timeouts; |
|
this._options = options || {}; |
|
this._maxRetryTime = options && options.maxRetryTime || Infinity; |
|
this._fn = null; |
|
this._errors = []; |
|
this._attempts = 1; |
|
this._operationTimeout = null; |
|
this._operationTimeoutCb = null; |
|
this._timeout = null; |
|
this._operationStart = null; |
|
|
|
if (this._options.forever) { |
|
this._cachedTimeouts = this._timeouts.slice(0); |
|
} |
|
} |
|
module.exports = RetryOperation; |
|
|
|
RetryOperation.prototype.reset = function() { |
|
this._attempts = 1; |
|
this._timeouts = this._originalTimeouts; |
|
} |
|
|
|
RetryOperation.prototype.stop = function() { |
|
if (this._timeout) { |
|
clearTimeout(this._timeout); |
|
} |
|
|
|
this._timeouts = []; |
|
this._cachedTimeouts = null; |
|
}; |
|
|
|
RetryOperation.prototype.retry = function(err) { |
|
if (this._timeout) { |
|
clearTimeout(this._timeout); |
|
} |
|
|
|
if (!err) { |
|
return false; |
|
} |
|
var currentTime = new Date().getTime(); |
|
if (err && currentTime - this._operationStart >= this._maxRetryTime) { |
|
this._errors.unshift(new Error('RetryOperation timeout occurred')); |
|
return false; |
|
} |
|
|
|
this._errors.push(err); |
|
|
|
var timeout = this._timeouts.shift(); |
|
if (timeout === undefined) { |
|
if (this._cachedTimeouts) { |
|
// retry forever, only keep last error |
|
this._errors.splice(this._errors.length - 1, this._errors.length); |
|
this._timeouts = this._cachedTimeouts.slice(0); |
|
timeout = this._timeouts.shift(); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
var self = this; |
|
var timer = setTimeout(function() { |
|
self._attempts++; |
|
|
|
if (self._operationTimeoutCb) { |
|
self._timeout = setTimeout(function() { |
|
self._operationTimeoutCb(self._attempts); |
|
}, self._operationTimeout); |
|
|
|
if (self._options.unref) { |
|
self._timeout.unref(); |
|
} |
|
} |
|
|
|
self._fn(self._attempts); |
|
}, timeout); |
|
|
|
if (this._options.unref) { |
|
timer.unref(); |
|
} |
|
|
|
return true; |
|
}; |
|
|
|
RetryOperation.prototype.attempt = function(fn, timeoutOps) { |
|
this._fn = fn; |
|
|
|
if (timeoutOps) { |
|
if (timeoutOps.timeout) { |
|
this._operationTimeout = timeoutOps.timeout; |
|
} |
|
if (timeoutOps.cb) { |
|
this._operationTimeoutCb = timeoutOps.cb; |
|
} |
|
} |
|
|
|
var self = this; |
|
if (this._operationTimeoutCb) { |
|
this._timeout = setTimeout(function() { |
|
self._operationTimeoutCb(); |
|
}, self._operationTimeout); |
|
} |
|
|
|
this._operationStart = new Date().getTime(); |
|
|
|
this._fn(this._attempts); |
|
}; |
|
|
|
RetryOperation.prototype.try = function(fn) { |
|
console.log('Using RetryOperation.try() is deprecated'); |
|
this.attempt(fn); |
|
}; |
|
|
|
RetryOperation.prototype.start = function(fn) { |
|
console.log('Using RetryOperation.start() is deprecated'); |
|
this.attempt(fn); |
|
}; |
|
|
|
RetryOperation.prototype.start = RetryOperation.prototype.try; |
|
|
|
RetryOperation.prototype.errors = function() { |
|
return this._errors; |
|
}; |
|
|
|
RetryOperation.prototype.attempts = function() { |
|
return this._attempts; |
|
}; |
|
|
|
RetryOperation.prototype.mainError = function() { |
|
if (this._errors.length === 0) { |
|
return null; |
|
} |
|
|
|
var counts = {}; |
|
var mainError = null; |
|
var mainErrorCount = 0; |
|
|
|
for (var i = 0; i < this._errors.length; i++) { |
|
var error = this._errors[i]; |
|
var message = error.message; |
|
var count = (counts[message] || 0) + 1; |
|
|
|
counts[message] = count; |
|
|
|
if (count >= mainErrorCount) { |
|
mainError = error; |
|
mainErrorCount = count; |
|
} |
|
} |
|
|
|
return mainError; |
|
};
|
|
|