@geersch/retry
Version:
Backoff strategies to use when retrying a function after a given delay.
33 lines • 1.66 kB
JavaScript
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