UNPKG

datum-focus

Version:

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

116 lines (99 loc) 2.83 kB
import { RetryOperation } from './operation'; interface RetryOptions { retries: number; factor: number; forever: boolean; minTimeout: number; maxTimeout: number; randomize: boolean; maxRetryTime: number; unref: any; } export function operation(options: Partial<RetryOptions>) { const timeouts = exports.timeouts(options); return new RetryOperation(timeouts, { forever: options && (options.forever || options.retries === Infinity), unref: options && options.unref, maxRetryTime: options && options.maxRetryTime }); }; export function timeouts(options: RetryOptions) { if (options instanceof Array) { return Object.assign([], options); } const opts: Pick< RetryOptions, 'retries' | 'factor' | 'minTimeout' | 'maxTimeout' | 'randomize' > & Partial<Pick<RetryOptions, 'unref'>> = { retries: 10, factor: 2, minTimeout: 1 * 1000, maxTimeout: Infinity, randomize: false }; for (const key in options) { opts[key] = options[key]; } if (opts.minTimeout > opts.maxTimeout) { throw new Error('minTimeout is greater than maxTimeout'); } const timeouts: number[] = []; for (let i: number = 0; i < opts.retries; i++) { timeouts.push(createTimeout(i, opts)); } if (options && options.forever && !timeouts.length) { timeouts.push(createTimeout(opts.retries, opts)); } // sort the array numerically ascending timeouts.sort(function (a, b) { return a - b; }); return timeouts; } export function createTimeout(attempt: number, opts: Pick< RetryOptions, 'factor' | 'minTimeout' | 'maxTimeout' | 'randomize' >) { const random = (opts.randomize) ? (Math.random() + 1) : 1; let timeout = Math.round(random * Math.max(opts.minTimeout, 1) * Math.pow(opts.factor, attempt)); timeout = Math.min(timeout, opts.maxTimeout); return timeout; }; export function wrap(obj: any, options: any, methods: any) { if (options instanceof Array) { methods = options; options = null; } if (!methods) { methods = []; for (const key in obj) { if (typeof obj[key] === 'function') { methods.push(key); } } } for (let i = 0; i < methods.length; i++) { const method = methods[i]; const original = obj[method]; obj[method] = function retryWrapper(original: any) { const op = exports.operation(options); const args = Array.prototype.slice.call(arguments, 1); const callback = args.pop(); args.push(function (err: any) { if (op.retry(err)) { return; } if (err) { arguments[0] = op.mainError(); } callback.apply(obj, arguments); }); op.attempt(function () { original.apply(obj, args); }); }.bind(obj, original); obj[method].options = options; } }