src/app/shared/utils/retry-once.ts
Properties |
|
| maxDelayMs |
maxDelayMs:
|
Type : number
|
| Optional |
|
Defined in src/app/shared/utils/retry-once.ts:3
|
|
Upper bound of the random pre-retry delay, in ms. Default 3000. |
| random |
random:
|
Type : function
|
| Optional |
|
Defined in src/app/shared/utils/retry-once.ts:5
|
|
Injectable for tests. Default Math.random. |
| wait |
wait:
|
Type : function
|
| Optional |
|
Defined in src/app/shared/utils/retry-once.ts:7
|
|
Injectable for tests. Default setTimeout-based wait. |
export interface RetryOnceOptions {
/** Upper bound of the random pre-retry delay, in ms. Default 3000. */
maxDelayMs?: number
/** Injectable for tests. Default Math.random. */
random?: () => number
/** Injectable for tests. Default setTimeout-based wait. */
wait?: (ms: number) => Promise<void>
}
const defaultWait = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms))
/**
* Runs requestFn; if it rejects, waits a random 0..maxDelayMs and tries
* exactly once more. A second rejection propagates as-is. Multiple
* concurrent DC instances (e.g. VA multi-page reports) can cause the
* startup request to time out even though a second attempt succeeds.
*/
export const retryOnce = async <T>(
requestFn: () => Promise<T>,
options?: RetryOnceOptions
): Promise<T> => {
const maxDelayMs = options?.maxDelayMs ?? 3000
const random = options?.random ?? Math.random
const wait = options?.wait ?? defaultWait
try {
return await requestFn()
} catch {
await wait(random() * maxDelayMs)
return requestFn()
}
}