Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { AsyncResult, Result } from "./result"; import { delay } from "./delay"; import { noop } from "./noop"; /** * @param error The error that resulted in the failure * @param attempt The 1-index attempt count */ export type OnIntermediateError<E> = (error: E, attempt: number) => void; export interface BackoffCallerOptions<E> { /** * Called when an attempt fails */ onIntermediateError?: OnIntermediateError<E>; /** * @default 5 */ maxAttempts?: number; /** * In milliseconds * @default 1000 */ initialTimeout?: number; /** * @default 2 */ scaleFactor?: number; } /** * Calls `fn` once and then again (with exponential delay between each attempt) up to `options.maxAttempts` times. * @param fn The function to repeatedly attempt * @returns The first success or the last failure */ export const backoffCaller = async <T, E>(fn: () => AsyncResult<T, E>, options?: BackoffCallerOptions<E>): AsyncResult<T, E> => { const { initialTimeout = 1000, maxAttempts = 5, onIntermediateError = noop as OnIntermediateError<E>, scaleFactor = 2, } = options ?? {}; let timeout = initialTimeout; let attempt = 0; let result: Result<T, E>; do { result = await fn(); if (result.callWasSuccessful) { return result; } onIntermediateError(result.error, attempt + 1); await delay(timeout); timeout *= scaleFactor; } while (attempt += 1, attempt < maxAttempts); return result; }; |