diff --git a/core/stdlib/src/async/retry/index.ts b/core/stdlib/src/async/retry/index.ts index a2a099f..1ac6ccb 100644 --- a/core/stdlib/src/async/retry/index.ts +++ b/core/stdlib/src/async/retry/index.ts @@ -9,35 +9,40 @@ export interface RetryOptions { } export type RetryFunction = ( - args: { + args: { count: number; stop: (error: any) => void; }, ) => Promise; -const RetryEarlyExit = Symbol('RetryEarlyExit'); +class RetryEarlyExitError { + cause: any; + constructor(cause: any) { + this.cause = cause; + } +} /** * @name retry * @category Async * @description Retries a function a specified number of times with a delay between each retry - * + * * @param {Promise} fn - The function to retry * @param {RetryOptions} options - The options for the retry * @returns {Promise} - The result of the function - * + * * @example * const result = await retry(() => { * return fetch('https://jsonplaceholder.typicode.com/todos/1') * .then(response => response.json()) * }); - * + * * @example * const result = await retry(() => { * return fetch('https://jsonplaceholder.typicode.com/todos/1') * .then(response => response.json()) * }, { times: 3, delay: 1000 }); - * + * * @since 0.0.8 */ export async function retry( @@ -50,24 +55,25 @@ export async function retry( shouldRetry, } = options; + const wrappedFn = tryIt(fn); + const delayFn = isFunction(delay) ? delay : null; + const delayMs = delayFn ? 0 : delay as number; + + const stop = (error?: any): never => { + throw new RetryEarlyExitError(error); + }; + + let lastError: Error | null = null; let count = 1; - let lastError: Error = new Error('Retry failed'); while (count <= times) { - const metadata = { - count, - stop: (error?: any) => { - throw { [RetryEarlyExit]: error }; - }, - }; - - const { error, data } = await tryIt(fn)(metadata); + const { error, data } = await wrappedFn({ count, stop }); if (!error) return data; - if (RetryEarlyExit in error) - throw error[RetryEarlyExit]; + if (error instanceof RetryEarlyExitError) + throw error.cause; if (shouldRetry && !shouldRetry(error, count)) throw error; @@ -77,12 +83,12 @@ export async function retry( // Don't delay after the last attempt if (count <= times) { - const delayMs = isFunction(delay) ? delay(count) : delay; - - if (delayMs > 0) - await sleep(delayMs); + const ms = delayFn ? delayFn(count) : delayMs; + + if (ms > 0) + await sleep(ms); } } - throw lastError; + throw lastError!; }