mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-19 16:39:50 +00:00
fix: stream cloud-init output instead of blind-polling on DigitalOcean (#1734)
Replace 60×5s blind poll loop ("Cloud-init in progress N/60") with
real-time streaming of /var/log/cloud-init-output.log via tail -f
over SSH. Users now see every apt-get, curl, and error as it happens.
Background checker exits as soon as .cloud-init-complete marker
appears. 5min timeout. Brief 30s fallback poll if streaming fails.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ac5e8495b1
commit
b50b27141c
2 changed files with 38 additions and 13 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@openrouter/spawn",
|
||||
"version": "0.6.8",
|
||||
"version": "0.6.9",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"spawn": "cli.js"
|
||||
|
|
|
|||
|
|
@ -760,29 +760,54 @@ export async function waitForCloudInit(
|
|||
await sleep(5000);
|
||||
}
|
||||
|
||||
logStep("Waiting for cloud-init to complete...");
|
||||
for (let attempt = 1; attempt <= 60; attempt++) {
|
||||
// Stream cloud-init output so the user sees progress in real time
|
||||
logStep("Streaming cloud-init output (timeout: 5min)...");
|
||||
const remoteScript = [
|
||||
'tail -f /var/log/cloud-init-output.log 2>/dev/null &',
|
||||
'TAIL_PID=$!',
|
||||
'for i in $(seq 1 150); do',
|
||||
' if [ -f /root/.cloud-init-complete ]; then',
|
||||
' kill $TAIL_PID 2>/dev/null; wait $TAIL_PID 2>/dev/null',
|
||||
' echo ""; echo "--- cloud-init complete ---"; exit 0',
|
||||
' fi',
|
||||
' sleep 2',
|
||||
'done',
|
||||
'kill $TAIL_PID 2>/dev/null; wait $TAIL_PID 2>/dev/null',
|
||||
'echo ""; echo "--- cloud-init timed out ---"; exit 1',
|
||||
].join("; ");
|
||||
|
||||
try {
|
||||
const proc = Bun.spawn(
|
||||
["ssh", ...SSH_OPTS, `root@${serverIp}`, remoteScript],
|
||||
{ stdio: ["ignore", "inherit", "inherit"] },
|
||||
);
|
||||
const exitCode = await proc.exited;
|
||||
if (exitCode === 0) {
|
||||
logInfo("Cloud-init complete");
|
||||
return;
|
||||
}
|
||||
logWarn("Cloud-init did not complete within 5 minutes");
|
||||
} catch {
|
||||
logWarn("Could not stream cloud-init log, falling back to polling...");
|
||||
}
|
||||
|
||||
// Brief fallback poll if streaming failed (e.g. log file not yet created)
|
||||
for (let attempt = 1; attempt <= 6; attempt++) {
|
||||
try {
|
||||
const proc = Bun.spawn(
|
||||
["ssh", ...SSH_OPTS, `root@${serverIp}`, "test -f /root/.cloud-init-complete && echo done"],
|
||||
{ stdio: ["ignore", "pipe", "pipe"] },
|
||||
);
|
||||
const stdout = await new Response(proc.stdout).text();
|
||||
const exitCode = await proc.exited;
|
||||
if (exitCode === 0 && stdout.includes("done")) {
|
||||
if ((await proc.exited) === 0 && stdout.includes("done")) {
|
||||
logInfo("Cloud-init complete");
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (attempt >= 60) {
|
||||
logWarn("Cloud-init marker not found, continuing anyway...");
|
||||
return;
|
||||
}
|
||||
logStep(`Cloud-init in progress (${attempt}/60)`);
|
||||
} catch { /* ignore */ }
|
||||
logStep(`Cloud-init in progress (${attempt}/6)`);
|
||||
await sleep(5000);
|
||||
}
|
||||
logWarn("Cloud-init marker not found, continuing anyway...");
|
||||
}
|
||||
|
||||
export async function runServer(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue