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.
		
		
		
		
		
			
		
			
				
					163 lines
				
				3.6 KiB
			
		
		
			
		
	
	
					163 lines
				
				3.6 KiB
			| 
											2 years ago
										 | 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; | ||
|  |   this._timer = 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.slice(0); | ||
|  | } | ||
|  | 
 | ||
|  | RetryOperation.prototype.stop = function() { | ||
|  |   if (this._timeout) { | ||
|  |     clearTimeout(this._timeout); | ||
|  |   } | ||
|  |   if (this._timer) { | ||
|  |     clearTimeout(this._timer); | ||
|  |   } | ||
|  | 
 | ||
|  |   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.push(err); | ||
|  |     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(0, this._errors.length - 1); | ||
|  |       timeout = this._cachedTimeouts.slice(-1); | ||
|  |     } else { | ||
|  |       return false; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   var self = this; | ||
|  |   this._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) { | ||
|  |       this._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; | ||
|  | }; |