@fluent-org/logger
Version:
A node fluent protocol compatible logger
85 lines • 3.67 kB
JavaScript
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
;