42 lines
1.3 KiB
TypeScript
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 };
|
|
}
|