fix(adapter-utils): await spawn metadata before close

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-07-18 20:19:05 +00:00
1 parent a87c6b41cd
commit 7edd4f57f4
2 files changed
+57 -33

No files matched your search

@@ -467,6 +467,23 @@ describe("runChildProcess", () => {
await expect(run).rejects.toThrow("database unavailable");
});
it("rejects when a no-stdin child exits before onSpawn persistence fails", async () => {
const run = runChildProcess(randomUUID(), process.execPath, ["-e", ""], {
cwd: process.cwd(),
env: {},
timeoutSec: 5,
graceSec: 1,
onLog: async () => {},
onLogError: () => {},
onSpawn: async () => {
await new Promise((resolve) => setTimeout(resolve, 100));
throw new Error("database unavailable after exit");
},
});
await expect(run).rejects.toThrow("database unavailable after exit");
});
it.skipIf(process.platform === "win32")("kills descendant processes on timeout via the process group", async () => {
let descendantPid: number | null = null;
+40 -33
View File
@@ -3182,16 +3182,20 @@ export async function runChildProcess(
signalRunningProcess({ child, processGroupId }, "SIGKILL");
reject(err instanceof Error ? err : new Error(String(err)));
};
const spawnPersistSucceeded = spawnPersistPromise.then(
() => true,
(err) => {
handleSpawnPersistenceFailure(err);
return false;
},
);
if (opts.stdin != null && stdin) {
void spawnPersistPromise
.then(() => {
if (child.killed || stdin.destroyed) return;
stdin.write(opts.stdin as string);
stdin.end();
})
.catch(handleSpawnPersistenceFailure);
} else {
void spawnPersistPromise.catch(handleSpawnPersistenceFailure);
void spawnPersistSucceeded.then((persisted) => {
if (!persisted) return;
if (child.killed || stdin.destroyed) return;
stdin.write(opts.stdin as string);
stdin.end();
});
}
child.on("error", (err: Error) => {
@@ -3217,30 +3221,33 @@ export async function runChildProcess(
clearTerminalCleanupTimers();
runningProcesses.delete(runId);
void logChain.finally(() => {
void Promise.resolve()
.then(() => target.cleanup?.())
.finally(() => {
resolve({
exitCode: code,
signal,
timedOut,
stdout,
stderr,
pid: child.pid ?? null,
startedAt,
terminalResultCleanup: terminalCleanupStarted
? {
kind: "terminal_result_cleanup",
stopped: true,
stopReason: UNMANAGED_BACKGROUND_TASK_STOP_REASON,
reason: UNMANAGED_BACKGROUND_TASK_LIVENESS_REASON,
terminalResultSeen,
signal: terminalCleanupSignal,
forceKilled: terminalCleanupForceKilled,
}
: null,
});
});
void spawnPersistSucceeded.then((persisted) => {
void Promise.resolve()
.then(() => target.cleanup?.())
.finally(() => {
if (!persisted) return;
resolve({
exitCode: code,
signal,
timedOut,
stdout,
stderr,
pid: child.pid ?? null,
startedAt,
terminalResultCleanup: terminalCleanupStarted
? {
kind: "terminal_result_cleanup",
stopped: true,
stopReason: UNMANAGED_BACKGROUND_TASK_STOP_REASON,
reason: UNMANAGED_BACKGROUND_TASK_LIVENESS_REASON,
terminalResultSeen,
signal: terminalCleanupSignal,
forceKilled: terminalCleanupForceKilled,
}
: null,
});
});
});
});
});
})