export interface RetryOptions {
maxAttempts: number;
baseDelay: number;
maxDelay: number;
backoffFactor: number;
}
export const defaultRetryOptions: RetryOptions = {
maxAttempts: 3,
baseDelay: 1000,
maxDelay: 30000,
backoffFactor: 2,
};
export async function withRetry<T>(
fn: () => Promise<T>,
options: Partial<RetryOptions> = {}
): Promise<T> {
const opts = { ...defaultRetryOptions, ...options };
let lastError: Error;
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
if (attempt === opts.maxAttempts) {
throw lastError;
}
const delay = Math.min(
opts.baseDelay * Math.pow(opts.backoffFactor, attempt - 1),
opts.maxDelay
);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError!;
}