UNPKG

@geersch/retry

Version:

Backoff strategies to use when retrying a function after a given delay.

33 lines 1.66 kB
import { defer, firstValueFrom, Observable, retry as retryOperator, tap, throwError, timer } from 'rxjs'; export async function retry(operation, backoffStrategy, options = {}) { let attempt = 1; return firstValueFrom(passRetryOperatorToPipe(defer(async () => operation(attempt)).pipe(tap({ error: () => (attempt += 1), })), backoffStrategy, options)); } export function passRetryOperatorToPipe(observable, backoffStrategy, { abortRetry, maxDelay = 30000, maxRetries = 5, scaleFactor = 1, unrecoverableErrors = [] }) { if (scaleFactor <= 0) { throw new TypeError(`Expected 'scaleFactor' to be a positive number greater than zero, got ${scaleFactor}.`); } const strategy = typeof backoffStrategy === 'function' ? new backoffStrategy() : backoffStrategy; const generator = strategy.getGenerator(maxRetries); return observable.pipe(retryOperator({ count: maxRetries, delay: (error, retryCount) => { const isUnrecoverable = unrecoverableErrors.some((errorConstructor) => error instanceof errorConstructor); if (isUnrecoverable || (abortRetry?.(error, retryCount) ?? false)) { return throwError(() => error); } const { value, done } = generator.next(); if (done) { return throwError(() => new Error(`The backoff strategy did not yield a delay for retry attempt ${retryCount}.`)); } let delay = value * scaleFactor; if (delay > maxDelay) { delay = maxDelay; } return timer(delay); }, })); } //# sourceMappingURL=retry.js.map