42 lines
1.3 KiB
TypeScript

import type { SpawnError } from "@uncaged/nerve-workflow-utils";
export async function runWithRetries(
run: () => Promise<
| { ok: true; stdout: string; stderr: string }
| { ok: false; error: SpawnError; lastStdout: string; lastStderr: string }
>,
maxAttempts: number,
): Promise<
| { ok: true; stdout: string; stderr: string; attemptsUsed: number }
| { ok: false; error: SpawnError; attemptsUsed: number; lastStdout: string; lastStderr: string }
> {
let attemptsUsed = 0;
let lastError: SpawnError | null = null;
let lastStdout = "";
let lastStderr = "";
while (attemptsUsed < maxAttempts) {
attemptsUsed += 1;
const current = await run();
if (current.ok) {
return { ok: true, stdout: current.stdout, stderr: current.stderr, attemptsUsed };
}
lastError = current.error;
lastStdout = current.lastStdout;
lastStderr = current.lastStderr;
if (attemptsUsed < maxAttempts) {
const backoffMs = Math.min(1000 * 2 ** (attemptsUsed - 1), 4000);
await new Promise((resolve) => setTimeout(resolve, backoffMs));
}
}
if (lastError === null) {
return {
ok: false,
error: { kind: "spawn_failed", message: "unknown retry failure" },
attemptsUsed,
lastStdout,
lastStderr,
};
}
return { ok: false, error: lastError, attemptsUsed, lastStdout, lastStderr };
}