// Exponential backoff with jitter
export interface RetryOptions {
maxRetries?: number;
baseDelay?: number;
maxDelay?: number;
factor?: number;
jitter?: boolean;
}
export async function withRetry<T>(
fn: () => Promise<T>,
options: RetryOptions = {}
): Promise<T> {
const {
maxRetries = 3,
baseDelay = 1000,
maxDelay = 10000,
factor = 2,
jitter = true
} = options;
let lastError: Error | undefined;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// If this was the last attempt, throw the error
if (attempt === maxRetries) {
throw error;
}
// Calculate delay with exponential backoff
let delay = Math.min(baseDelay * Math.pow(factor, attempt), maxDelay);
// Add jitter if enabled
if (jitter) {
delay = delay * (0.5 + Math.random() * 0.5);
}
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}