mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
fix(adapter-utils): await spawn metadata before close
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user