refactor(core/stdlib): improve retry function implementation and error handling

This commit is contained in:
2026-03-26 06:09:54 +07:00
parent a61fb85088
commit 8d8ea734d1
+28 -22
View File
@@ -9,35 +9,40 @@ export interface RetryOptions {
}
export type RetryFunction<Return> = (
args: {
args: {
count: number;
stop: (error: any) => void;
},
) => Promise<Return>;
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<unknown>} fn - The function to retry
* @param {RetryOptions} options - The options for the retry
* @returns {Promise<unknown>} - 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<Return>(
@@ -50,24 +55,25 @@ export async function retry<Return>(
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<Return>(
// 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!;
}