refactor: format restart handoff diagnostics

This commit is contained in:
Shakker
2026-05-05 07:48:41 +01:00
parent 4a24b6dbc4
commit 3e53580d63
2 changed files with 52 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
consumeGatewayRestartHandoffForExitedProcessSync,
formatGatewayRestartHandoffDiagnostic,
GATEWAY_SUPERVISOR_RESTART_HANDOFF_FILENAME,
GATEWAY_SUPERVISOR_RESTART_HANDOFF_KIND,
readGatewayRestartHandoffSync,
@@ -248,4 +249,26 @@ describe("gateway restart handoff", () => {
}),
).toMatchObject({ pid: 12_345 });
});
it("formats a concise diagnostic line for status surfaces", () => {
expect(
formatGatewayRestartHandoffDiagnostic(
{
kind: GATEWAY_SUPERVISOR_RESTART_HANDOFF_KIND,
version: 1,
intentId: "intent-1",
pid: 12_345,
createdAt: 10_000,
expiresAt: 70_000,
reason: "plugin source changed",
source: "plugin-change",
restartKind: "full-process",
supervisorMode: "launchd",
},
12_500,
),
).toBe(
"Recent restart handoff: full-process via launchd; source=plugin-change; reason=plugin source changed; pid=12345; age=2s; expiresIn=57s",
);
});
});

View File

@@ -39,6 +39,35 @@ export type GatewayRestartHandoff = {
supervisorMode: GatewayRestartHandoffSupervisorMode;
};
function formatShortDuration(ms: number): string {
const clamped = Math.max(0, Math.floor(ms));
if (clamped < 1000) {
return `${clamped}ms`;
}
const seconds = Math.floor(clamped / 1000);
if (seconds < 60) {
return `${seconds}s`;
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return remainingSeconds === 0 ? `${minutes}m` : `${minutes}m ${remainingSeconds}s`;
}
export function formatGatewayRestartHandoffDiagnostic(
handoff: GatewayRestartHandoff,
now = Date.now(),
): string {
const detail = [
`${handoff.restartKind} via ${handoff.supervisorMode}`,
`source=${handoff.source}`,
handoff.reason ? `reason=${handoff.reason}` : undefined,
`pid=${handoff.pid}`,
`age=${formatShortDuration(now - handoff.createdAt)}`,
`expiresIn=${formatShortDuration(handoff.expiresAt - now)}`,
].filter((value): value is string => Boolean(value));
return `Recent restart handoff: ${detail.join("; ")}`;
}
function resolveGatewayRestartHandoffPath(env: NodeJS.ProcessEnv = process.env): string {
return path.join(resolveStateDir(env), GATEWAY_SUPERVISOR_RESTART_HANDOFF_FILENAME);
}