UNPKG

@poomcha/retrier

Version:

Retry synchronous or asynchronous functions.

585 lines (582 loc) 18.9 kB
// src/helpers/Utils.ts var UtilsNumber = class { /** * Returns true if n is a safe integer, between Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER. * @param n any * @returns boolean */ static isInteger(n) { return Number.isSafeInteger(n); } /** * Returns true if n is positive. * @param n number * @returns boolean */ static isPositive(n) { return n >= 0; } /** * Returns true if n is an integer. Else raise NonIntegerError. * @param n number * @returns boolean * @throws NonIntegerError */ static checkIntegerNumber(n) { if (this.isInteger(n)) return n; throw new Error("NonSafeIntegerError"); } /** * Returns true if n is positive. Else raise NonPositiveError. * @param n number * @returns boolean * @throws NonPositiveError */ static checkPositiveNumber(n) { if (this.isPositive(n)) return n; throw new Error("NonPositiveError"); } /** * Returns true if n is a positive integer * @param n any * @returns boolean * @throws */ static checkIntegerPositive(n) { try { return this.checkPositiveNumber(this.checkIntegerNumber(n)); } catch (error) { throw error; } } }; var UtilsCallback = class { /** * Call a callback function with or without its arguments synchronously and return its result or throw error. * * @param callback * @param args Optionnal */ static callSyncCallback(callback, args) { try { if (args) { return callback(...args); } return callback(); } catch (error) { throw error; } } /** * Call a callback function with or without its arguments asynchronously and return its result or throw error. * * @param callback * @param args Optionnal */ static async callAsyncCallback(callback, args) { try { if (args) { return await callback(...args); } return await callback(); } catch (error) { throw error; } } }; // src/retrier/Retrier.ts var Retrier = class _Retrier { //#region Members _maxRetries = 0; _maxRetriesDefault = 2; _delay = 0; _delayDefault = 0; _onSuccess = void 0; _onFailure = void 0; //#endregion //#region Constructor /** * Constructs a new Retrier instance with optional configuration options. * @constructor * * @param options - Optional configuration options. * @param options.maxRetries - The maximum number of retries. * @param options.delay - Delay between two retries in ms. * @param options.onSuccess - onSuccess callback, can override default return. * @param options.onFailure - onFailure callback, can override default error throwing. * @throws Will throw an error if the maxRetries or delay are not valid positive integer * [0, Number.MAX_SAFE_INTEGER]. */ constructor(options) { if (options) { const { maxRetries, delay, onSuccess, onFailure } = options; try { if (maxRetries) this.setMaxRetries(maxRetries); else this.setMaxRetries(this._maxRetriesDefault); if (delay) this.setDelay(delay); else this.setDelay(this._delayDefault); if (onSuccess) this.setOnSuccess(onSuccess); if (onFailure) this.setOnFailure(onFailure); } catch (error) { throw error; } } else { try { this.setMaxRetries(this._maxRetriesDefault); this.setDelay(this._delayDefault); } catch (error) { throw error; } } } //#endregion //#region Getters /** * Gets the maximum number of retries. * * @returns The maximum number of retries. */ getMaxRetries() { return this._maxRetries; } /** * Gets the delay between retries. * * @returns Delay between retries. */ getDelay() { return this._delay; } /** * Get the _onSuccess private member. * * @returns _onSuccess member */ getOnSuccess() { return this._onSuccess; } /** * Get the _onFailure private member. * * @returns _onFailure member. */ getOnFailure() { return this._onFailure; } //#endregion //#region Setters /** * Sets the maximum number of retries. * * @param n - The number of retries to set. * @throws Will throw an error if the number is not a valid positive integer. */ setMaxRetries(n) { try { this._maxRetries = UtilsNumber.checkIntegerNumber(n); } catch (error) { throw error; } } /** * Sets the delay between retries. * * @param delay - Delay between retries. * @throws Will throw an error if the number is not a valid positive integer */ setDelay(delay) { try { this._delay = UtilsNumber.checkIntegerNumber(delay); } catch (error) { throw error; } } /** * Sets the _onSuccess member * * @param onSuccess * @param onSuccess.callback Callback to call on success * @param onSuccess.args Arguments to pass to the callback * @param onSuccess.override If true, override default behaviour of retry functions */ setOnSuccess(onSuccess) { this._onSuccess = onSuccess; return; } /** * Sets the _onFailure member * * @param onFailure * @param onFailure.callback Callback to call on failure * @param onFailure.args Arguments to pass to the callback * @param onFailure.override If true, override default behaviour of retry functions */ setOnFailure(onFailure) { this._onFailure = onFailure; return; } //#endregion //#region Static Methods /** * Retries a synchronous operation, with a specified number of retries. * Returns the result of the operation as soon as it succeed, or throws * operation's error. * Give access to onSuccess and onFailure optionnal handlers to handle * success or failure. * onSuccess and onFailure are given operation result as first argument. * * @see [source](https://github.com/Poomcha/retrier) * * * @param maxRetries - Positive integer, max number of retries <code>(Number[0, MAX_SAFE_INTEGER])</code>. * @param callback - Function to retry. * @param args - Optionnal arguments for callback. * * * @param options - Optionnal options. * * * @param options.onSuccess - * @param options.onSuccess.callback - Function to run on success. * @param options.onSuccess.args - Optionnal arguments for onSuccess.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onSuccess.override - Optionnal boolean, if true retrySync will return options.onSuccess.callback result. * * @param options.Failure - * @param options.onFailure.callback - Function to run on failure. * @param options.onFailure.args - Optionnal arguments for onFailure.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onFailure.override - Boolean, if true retrySync will return options.onFailure.callback result. * * * @returns callback result or options.onSuccess.callback result or options.onFailure.callback result. * * * @throw callback error or options.onSuccess.callback error or options.onFailure.callback error. */ static retryStaticSync(maxRetries, callback, args, options) { try { return _Retrier._retrySync(callback, maxRetries, args, options); } catch (error) { throw error; } } /** * Retries an asynchronous operation, with a specified number of retries. * Returns the result of the operation as soon as it succeed, or throws * operation's error. * Give access to onSuccess and onFailure optionnal handlers to handle * success or failure. * onSuccess and onFailure are given operation result as first argument. * * @see [source](https://github.com/Poomcha/retrier) * * @param maxRetries - Positive integer, max number of retries <code>(Number[0, MAX_SAFE_INTEGER])</code>. * @param callback - Function to retry. * @param args - Optionnal arguments for callback. * * * @param options - Optionnal options. * * @param options.delay - Positive integer, delay between 2 retry. * * @param options.onSuccess - * @param options.onSuccess.callback - Function to run on success. * @param options.onSuccess.args - Optionnal arguments for onSuccess.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onSuccess.override - Optionnal boolean, if true retrySync will return options.onSuccess.callback result. * * @param options.Failure - * @param options.onFailure.callback - Function to run on failure. * @param options.onFailure.args - Optionnal arguments for onFailure.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onFailure.override - Boolean, if true retrySync will return options.onFailure.callback result. * * * @returns callback result or options.onSuccess.callback result or options.onFailure.callback result. * * * @throw callback error or options.onSuccess.callback error or options.onFailure.callback error. */ static async retryStaticAsync(maxRetries, callback, args, options) { try { return await _Retrier._retryAsync(callback, maxRetries, args, options); } catch (error) { throw error; } } //#endregion //#region Public Methods /** * Retries a synchronous operation, with a specified number of retries. * Returns the result of the operation as soon as it succeed, or throws * operation's error. * Give access to onSuccess and onFailure optionnal handlers to handle * success or failure. * onSuccess and onFailure are given operation result as first argument. * * @see [source](https://github.com/Poomcha/retrier) * * * @param callback - Function to retry. * @param args - Optionnal arguments for callback. * * * @param options - Optionnal options, overule instance configuration. * * @param options.maxRetries - Positive integer, max number of retries <code>(Number[0, MAX_SAFE_INTEGER])</code>. * * @param options.onSuccess - * @param options.onSuccess.callback - Function to run on success. * @param options.onSuccess.args - Optionnal arguments for onSuccess.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onSuccess.override - Optionnal boolean, if true retrySync will return options.onSuccess.callback result. * * @param options.Failure - * @param options.onFailure.callback - Function to run on failure. * @param options.onFailure.args - Optionnal arguments for onFailure.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onFailure.override - Boolean, if true retrySync will return options.onFailure.callback result. * * * @returns callback result or options.onSuccess.callback result or options.onFailure.callback result. * * * @throw callback error or options.onSuccess.callback error or options.onFailure.callback error. */ retrySync(callback, args, options) { try { const computedOptions = this.makeOptionsSync( options ); return _Retrier._retrySync( callback, computedOptions.maxRetries, args, computedOptions ); } catch (error) { throw error; } } /** * Retries an asynchronous operation, with a specified number of retries. * Returns the result of the operation as soon as it succeed, or throws * operation's error. * Give access to onSuccess and onFailure optionnal handlers to handle * success or failure. * onSuccess and onFailure are given operation result as first argument. * * @see [source](https://github.com/Poomcha/retrier) * * @param callback - Function to retry. * @param args - Optionnal arguments for callback. * * * @param options - Optionnal options. * * @param options.maxRetries - Positive integer, max number of retries <code>(Number[0, MAX_SAFE_INTEGER])</code>. * * @param options.delay - Positive integer, delay between 2 retry. * * @param options.onSuccess - * @param options.onSuccess.callback - Function to run on success. * @param options.onSuccess.args - Optionnal arguments for onSuccess.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onSuccess.override - Optionnal boolean, if true retrySync will return options.onSuccess.callback result. * * @param options.Failure - * @param options.onFailure.callback - Function to run on failure. * @param options.onFailure.args - Optionnal arguments for onFailure.callback, * first argument will always be global callback result as <code>[res, ...args]</code>. * @param options.onFailure.override - Boolean, if true retrySync will return options.onFailure.callback result. * * * @returns callback result or options.onSuccess.callback result or options.onFailure.callback result. * * * @throw callback error or options.onSuccess.callback error or options.onFailure.callback error. */ async retryAsync(callback, args, options) { try { const computedOptions = this.makeOptionsAsync( options ); return await _Retrier._retryAsync( callback, computedOptions.maxRetries, args, computedOptions ); } catch (error) { throw error; } } //#endregion //#region Private Methods /** * Internal method to retry a synchronous operation. * * @param callback - The callback function to retry. * @param retry - The current retry count. * @param args - Optional arguments to pass to the callback. * @param options - Optional retry options. * @returns The result of the callback function. * @throws Will throw an error if all retries fail. */ static _retrySync(callback, retry, args, options) { let onSuccess; let onFailure; if (options) { onSuccess = options.onSuccess; onFailure = options.onFailure; } try { const res = UtilsCallback.callSyncCallback(callback, args); if (onSuccess) { const onSuccessRes = UtilsCallback.callSyncCallback( onSuccess.callback, [res, ...onSuccess.args || []] ); if (onSuccess.override) { return onSuccessRes; } } return res; } catch (error) { if (retry > 0) { return _Retrier._retrySync(callback, retry - 1, args, options); } if (onFailure) { const onFailureRes = UtilsCallback.callSyncCallback( onFailure.callback, [error, ...onFailure.args || []] ); if (onFailure.override) { return onFailureRes; } } throw error; } } /** * Internal method to retry an asynchronous operation. * * @param callback - The callback function to retry. * @param retry - The current retry count. * @param args - Optional arguments to pass to the callback. * @param options - Optional retry options. * @returns A promise that resolves to the result of the callback function. * @throws Will throw an error if all retries fail. */ static async _retryAsync(callback, retry, args, options) { let onSuccess; let onFailure; if (options) { onSuccess = options.onSuccess; onFailure = options.onFailure; } try { const res = await UtilsCallback.callAsyncCallback(callback, args); if (onSuccess) { const onSuccessRes = await UtilsCallback.callAsyncCallback( onSuccess.callback, [res, ...onSuccess.args || []] ); if (onSuccess.override) { return onSuccessRes; } } return res; } catch (error) { if (retry > 0) { if (options && options.delay && options.delay > 0) { await new Promise((resolve) => { const timeout = setTimeout(resolve, options.delay); }); } return _Retrier._retryAsync(callback, retry - 1, args, options); } if (onFailure) { const onFailureRes = await UtilsCallback.callAsyncCallback( onFailure.callback, [error, ...onFailure.args || []] ); if (onFailure.override) { return onFailureRes; } } throw error; } } /** * Internal method to set options configuration for non static sync methods * * @param options */ makeOptionsSync(options) { let computedOptions = options; if (computedOptions) { if (!computedOptions.maxRetries) computedOptions.maxRetries = this.getMaxRetries(); else { try { UtilsNumber.checkIntegerPositive(computedOptions.maxRetries); } catch (error) { throw error; } } if (!computedOptions.onSuccess) computedOptions.onSuccess = this.getOnSuccess(); if (!computedOptions.onFailure) computedOptions.onFailure = this.getOnFailure(); } else { computedOptions = { maxRetries: this.getMaxRetries(), onSuccess: this.getOnSuccess(), onFailure: this.getOnFailure() }; } return computedOptions; } /** * Internal method to set options configuration for non static async methods * * @param options */ makeOptionsAsync(options) { let computedOptions = options; if (computedOptions) { try { if (!computedOptions.maxRetries) computedOptions.maxRetries = this.getMaxRetries(); else UtilsNumber.checkIntegerPositive(computedOptions.maxRetries); if (!computedOptions.delay) computedOptions.delay = this.getDelay(); else UtilsNumber.checkIntegerPositive(computedOptions.delay); } catch (error) { throw error; } if (!computedOptions.onSuccess) computedOptions.onSuccess = this.getOnSuccess(); if (!computedOptions.onFailure) computedOptions.onFailure = this.getOnFailure(); } else { computedOptions = { maxRetries: this.getMaxRetries(), delay: this.getDelay(), onSuccess: this.getOnSuccess(), onFailure: this.getOnFailure() }; } return computedOptions; } //#endregion }; // index.ts var retrySync = Retrier.retryStaticSync; var retryAsync = Retrier.retryStaticAsync; export { Retrier, retryAsync, retrySync };