Add retrying. Improve diff format
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import { log } from "./cli.ts";
|
||||
|
||||
export type RetryOptions = {
|
||||
maxAttempts?: number;
|
||||
delayMs?: number;
|
||||
shouldRetry?: (error: unknown) => boolean;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
const defaultShouldRetry = (error: unknown): boolean => {
|
||||
if (!(error instanceof Error)) return false;
|
||||
// retry on transient network errors
|
||||
return (
|
||||
error.name === "AbortError" ||
|
||||
error.message.includes("fetch failed") ||
|
||||
error.message.includes("ECONNRESET") ||
|
||||
error.message.includes("ETIMEDOUT")
|
||||
);
|
||||
};
|
||||
|
||||
export async function retry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
||||
const maxAttempts = options.maxAttempts ?? 3;
|
||||
const delayMs = options.delayMs ?? 1000;
|
||||
const shouldRetry = options.shouldRetry ?? defaultShouldRetry;
|
||||
const label = options.label ?? "operation";
|
||||
|
||||
let lastError: unknown;
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
|
||||
if (attempt === maxAttempts || !shouldRetry(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const delay = delayMs * attempt;
|
||||
log.warning(`» ${label} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay}ms...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user