UNPKG

@fluent-org/logger

Version:
85 lines 3.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventRetrier = void 0; const error_1 = require("./error"); const util_1 = require("./util"); /** * Provides retry logic for a promise, with failure cases */ class EventRetrier { constructor(opts = {}) { this.options = { attempts: 4, backoff: 2, delay: 100, minDelay: -Infinity, maxDelay: +Infinity, onError: () => { }, ...(opts || {}), }; this.cancelWait = util_1.pDefer(); } /** * Causes ongoing retry handlers to cancel their timeout and immediately retry * @returns a Promise which completes after all handlers have retried once. */ async shortCircuit() { const { resolve } = this.cancelWait; // Reinitialize the promise so this class can continue to be reused this.cancelWait = util_1.pDefer(); resolve(); // The Promise.resolve PromiseJob will be enqueued after all the resolve functions on cancelWait. // Promise.race([a,b]) then enqueues another PromiseJob since it needs to resolve its promise. // We want the shutdown promise to resolve after the Promise.race.then call, meaning we enqueue a // new PromiseJob as well, which is enqueued after Promise.race enqueues it's jobs await Promise.resolve(); } /** * Exits all ongoing retry handlers with an error * * @returns A promise which completes once all retry handlers have exited. */ async shutdown() { const { reject } = this.cancelWait; // Reinitialize the promise so this class can continue to be reused this.cancelWait = util_1.pDefer(); reject(new error_1.RetryShutdownError("Retries were shut down")); // The Promise.resolve PromiseJob will be enqueued after all the resolve functions on cancelWait. // Promise.race([a,b]) then enqueues another PromiseJob since it needs to resolve its promise. // We want the shutdown promise to resolve after the Promise.race.then call, meaning we enqueue a // new PromiseJob as well, which is enqueued after Promise.race enqueues it's jobs await Promise.resolve(); } /** * Retry the promise * * Attempts the promise in an infinite loop, and retries according to the logic in EventRetryOptions * @param makePromise An async function to retry * @returns A Promise which succeeds if the async function succeeds, or has exhausted retry attempts */ async retryPromise(makePromise) { let retryAttempts = 0; do { try { return await makePromise(); } catch (e) { // Ignore DroppedError by default, this prevents us from requeuing on shutdown or queue clear if (e instanceof error_1.DroppedError) { throw e; } if (retryAttempts >= this.options.attempts) { throw e; } this.options.onError(e); const retryInterval = Math.min(this.options.maxDelay, Math.max(this.options.minDelay, this.options.backoff ** retryAttempts * this.options.delay)); retryAttempts += 1; // Await the retry promise, but short circuiting is OK await util_1.awaitAtMost(this.cancelWait.promise, retryInterval); } // eslint-disable-next-line no-constant-condition } while (true); } } exports.EventRetrier = EventRetrier; //# sourceMappingURL=event_retrier.js.map