UNPKG

datum-focus

Version:

Data shape, model, metadata, JSON, JSON Schema, GraphQL, MongoDB query and aggregations, iterator generators

157 lines (128 loc) 3.54 kB
export class RetryOperation { _originalTimeouts: any; _timeouts: any; _options: any; _maxRetryTime: any; _fn: any | null = null; _errors: any[] = []; _attempts: number = 1; _operationTimeout: any | null = null; _operationTimeoutCb: any | null = null; _timeout: any | null = null; _operationStart: any | null = null; _timer: any | null = null; _cachedTimeouts: any; constructor(timeouts: any, options: any) { // 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; if (this._options.forever) { this._cachedTimeouts = this._timeouts.slice(0); } } reset() { this._attempts = 1; this._timeouts = this._originalTimeouts.slice(0); } stop() { if (this._timeout) { clearTimeout(this._timeout); } if (this._timer) { clearTimeout(this._timer); } this._timeouts = []; this._cachedTimeouts = null; } retry(err: any) { if (this._timeout) { clearTimeout(this._timeout); } if (!err) { return false; } const 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); let 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; } } const 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; } attempt(fn: any, timeoutOps?: any) { this._fn = fn; if (timeoutOps) { if (timeoutOps.timeout) { this._operationTimeout = timeoutOps.timeout; } if (timeoutOps.cb) { this._operationTimeoutCb = timeoutOps.cb; } } const self = this; if (this._operationTimeoutCb) { this._timeout = setTimeout(function () { self._operationTimeoutCb(); }, self._operationTimeout); } this._operationStart = new Date().getTime(); this._fn(this._attempts); }; errors() { return this._errors; } attempts() { return this._attempts; } mainError() { if (this._errors.length === 0) { return null; } const counts: any = {}; let mainError: any = null; let mainErrorCount = 0; for (let i = 0; i < this._errors.length; i++) { const error = this._errors[i]; const message = error.message; const count = (counts[message] || 0) + 1; counts[message] = count; if (count >= mainErrorCount) { mainError = error; mainErrorCount = count; } } return mainError; } }