Make daemon shutdowns easier to diagnose (#1790)
* fix(daemon): log stop reasons and client identity Record websocket client identity, process memory/uptime, and shutdown reasons across CLI, desktop, supervisor, and worker paths so daemon drops can be traced from the triggering client to worker termination. * fix(daemon): keep shutdown diagnostics in sync Test drift: supervisor and relay tests still asserted the old log text and metadata shape after shutdown diagnostics started logging structured reasons and relay connection ids. Update those assertions to the new diagnostic contract. Also centralize client lifecycle reason normalization and derive desktop daemon stop reasons from one tuple so future changes cannot silently drift.
This commit is contained in:
@@ -17,6 +17,8 @@ const mocks = vi.hoisted(() => ({
|
||||
runExternalCliJsonCommand: vi.fn(),
|
||||
runExternalCliTextCommand: vi.fn(),
|
||||
spawnProcess: vi.fn(),
|
||||
logInfo: vi.fn(),
|
||||
logError: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("electron", () => ({
|
||||
@@ -30,7 +32,7 @@ vi.mock("electron", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("electron-log/main", () => ({
|
||||
default: { info: vi.fn(), error: vi.fn() },
|
||||
default: { info: mocks.logInfo, error: mocks.logError },
|
||||
}));
|
||||
|
||||
vi.mock("@getpaseo/server", () => ({
|
||||
@@ -101,6 +103,8 @@ describe("daemon-manager commands", () => {
|
||||
mocks.runExternalCliJsonCommand.mockReset();
|
||||
mocks.runExternalCliTextCommand.mockReset();
|
||||
mocks.spawnProcess.mockReset();
|
||||
mocks.logInfo.mockReset();
|
||||
mocks.logError.mockReset();
|
||||
rmSync(mocks.paseoHome, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
@@ -194,6 +198,31 @@ describe("daemon-manager commands", () => {
|
||||
"status",
|
||||
"--json",
|
||||
]);
|
||||
expect(mocks.logInfo).toHaveBeenCalledWith(
|
||||
"[desktop daemon]",
|
||||
"desktop daemon stop requested",
|
||||
expect.objectContaining({
|
||||
reason: "manual_ipc",
|
||||
statusBefore: expect.objectContaining({
|
||||
status: "running",
|
||||
pid: 4242,
|
||||
serverId: "server-1",
|
||||
desktopManaged: true,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(mocks.logInfo).toHaveBeenCalledWith(
|
||||
"[desktop daemon]",
|
||||
"desktop daemon stop completed",
|
||||
expect.objectContaining({
|
||||
reason: "manual_ipc",
|
||||
cliResult: { action: "stopped" },
|
||||
statusAfter: expect.objectContaining({
|
||||
status: "stopped",
|
||||
serverId: null,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("routes stale reachable desktop daemon stops through external CLI daemon stop", async () => {
|
||||
@@ -239,6 +268,39 @@ describe("daemon-manager commands", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("records the renderer stop reason when stopping the desktop daemon", async () => {
|
||||
mocks.runExternalCliJsonCommand
|
||||
.mockResolvedValueOnce({
|
||||
localDaemon: "running",
|
||||
serverId: "server-1",
|
||||
pid: 4242,
|
||||
listen: "127.0.0.1:6767",
|
||||
desktopManaged: true,
|
||||
})
|
||||
.mockResolvedValueOnce({ action: "stopped", reason: "lifecycle_shutdown_rpc" })
|
||||
.mockResolvedValueOnce({
|
||||
localDaemon: "stopped",
|
||||
serverId: "",
|
||||
});
|
||||
const handlers = createDaemonCommandHandlers();
|
||||
|
||||
await handlers.stop_desktop_daemon({ reason: "host_remove" });
|
||||
|
||||
expect(mocks.logInfo).toHaveBeenCalledWith(
|
||||
"[desktop daemon]",
|
||||
"desktop daemon stop requested",
|
||||
expect.objectContaining({ reason: "host_remove" }),
|
||||
);
|
||||
expect(mocks.logInfo).toHaveBeenCalledWith(
|
||||
"[desktop daemon]",
|
||||
"desktop daemon stop completed",
|
||||
expect.objectContaining({
|
||||
reason: "host_remove",
|
||||
cliResult: { action: "stopped", reason: "lifecycle_shutdown_rpc" },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("uses a stale reachable desktop daemon when the version matches", async () => {
|
||||
mocks.runExternalCliJsonCommand.mockResolvedValue({
|
||||
localDaemon: "stale_pid",
|
||||
|
||||
Reference in New Issue
Block a user