Fix release-blocking CI failures
This commit is contained in:
@@ -359,8 +359,9 @@ describe("daemon-manager commands", () => {
|
||||
|
||||
expect(thrown).toBeInstanceOf(Error);
|
||||
const message = thrown?.message ?? "";
|
||||
const recentLogsLabel = message.match(/Recent logs \(([^)]*)\):/)?.[1];
|
||||
expect(message).toContain("Daemon failed to start: exit code 1");
|
||||
expect(message).toContain(`Recent logs (${mocks.paseoHome}/daemon.log):`);
|
||||
expect(recentLogsLabel?.split(/[\\/]/).at(-1)).toBe("daemon.log");
|
||||
expect(message).toContain("recent daemon failure");
|
||||
expect(mocks.spawnProcess).toHaveBeenCalledWith(
|
||||
"node",
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import type { Event as OpenCodeEvent, OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
||||
|
||||
import type { OpenCodeRuntime, OpenCodeServerAcquisition } from "../runtime.js";
|
||||
|
||||
@@ -92,7 +92,7 @@ export class TestOpenCodeClient {
|
||||
sessionMessagesResponse: OpenCodeResponse = { data: [] };
|
||||
sessionPromptAsyncEvents: unknown[] = [idleEvent()];
|
||||
sessionPromptAsyncResponse: OpenCodeResponse = {};
|
||||
sessionSummarizeEvents: OpenCodeEvent[] = [];
|
||||
sessionSummarizeEvents: unknown[] = [idleEvent()];
|
||||
sessionSummarizeResponse: OpenCodeResponse = { data: {} };
|
||||
sessionUpdateResponse: OpenCodeResponse = {};
|
||||
private readonly queuedEventStream = createQueuedEventStream();
|
||||
|
||||
@@ -173,13 +173,17 @@ async function main() {
|
||||
|
||||
const supervisorPid = process.ppid;
|
||||
let lastSupervisorHeartbeatAt = Date.now();
|
||||
let supervisorShutdownRequested = false;
|
||||
const requestSupervisorShutdown = (reason: string) => {
|
||||
if (supervisorShutdownRequested) {
|
||||
let supervisorExitRequested = false;
|
||||
const exitAfterSupervisorLoss = () => {
|
||||
if (supervisorExitRequested) {
|
||||
return;
|
||||
}
|
||||
supervisorShutdownRequested = true;
|
||||
beginShutdown(reason);
|
||||
supervisorExitRequested = true;
|
||||
|
||||
// The supervisor owns the worker's stdout/stderr pipes. Once it is gone,
|
||||
// logging during graceful shutdown can block on the broken pipe and leave
|
||||
// the daemon orphaned, so supervisor loss is a hard process boundary.
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
process.on("message", (message: unknown) => {
|
||||
@@ -192,13 +196,19 @@ async function main() {
|
||||
lastSupervisorHeartbeatAt = Date.now();
|
||||
}
|
||||
});
|
||||
process.on("disconnect", () => requestSupervisorShutdown("supervisor disconnect"));
|
||||
process.on("disconnect", exitAfterSupervisorLoss);
|
||||
|
||||
const timer = setInterval(() => {
|
||||
const ipcConnected = typeof process.connected === "boolean" ? process.connected : true;
|
||||
const heartbeatExpired = Date.now() - lastSupervisorHeartbeatAt > 3500;
|
||||
if (ipcConnected === false || !isPidAlive(supervisorPid) || heartbeatExpired) {
|
||||
requestSupervisorShutdown("supervisor disconnect");
|
||||
const supervisorChanged = process.ppid !== supervisorPid;
|
||||
if (
|
||||
ipcConnected === false ||
|
||||
supervisorChanged ||
|
||||
!isPidAlive(supervisorPid) ||
|
||||
heartbeatExpired
|
||||
) {
|
||||
exitAfterSupervisorLoss();
|
||||
}
|
||||
}, 1000);
|
||||
timer.unref();
|
||||
|
||||
Reference in New Issue
Block a user