import { describe, expect, it } from "vitest" ;
import { createRunRegistry } from "./registry.js" ;
type RunRegistry = ReturnType<typeof createRunRegistry>;
function addRunningRecord(
registry: RunRegistry,
params: {
runId: string;
sessionId: string;
startedAtMs: number;
scopeKey?: string;
backendId?: string;
},
) {
registry.add({
runId: params.runId,
sessionId: params.sessionId,
backendId: params.backendId ?? "b1" ,
scopeKey: params.scopeKey,
state: "running" ,
startedAtMs: params.startedAtMs,
lastOutputAtMs: params.startedAtMs,
createdAtMs: params.startedAtMs,
updatedAtMs: params.startedAtMs,
});
}
describe("process supervisor run registry" , () => {
it("finalize is idempotent and preserves first terminal metadata" , () => {
const registry = createRunRegistry();
addRunningRecord(registry, { runId: "r1" , sessionId: "s1" , startedAtMs: 1 });
const first = registry.finalize("r1" , {
reason: "overall-timeout" ,
exitCode: null ,
exitSignal: "SIGKILL" ,
});
const second = registry.finalize("r1" , {
reason: "manual-cancel" ,
exitCode: 0 ,
exitSignal: null ,
});
expect(first).not.toBeNull();
expect(first?.firstFinalize).toBe(true );
expect(first?.record.terminationReason).toBe("overall-timeout" );
expect(first?.record.exitCode).toBeNull();
expect(first?.record.exitSignal).toBe("SIGKILL" );
expect(second).not.toBeNull();
expect(second?.firstFinalize).toBe(false );
expect(second?.record.terminationReason).toBe("overall-timeout" );
expect(second?.record.exitCode).toBeNull();
expect(second?.record.exitSignal).toBe("SIGKILL" );
});
it("prunes oldest exited records once retention cap is exceeded" , () => {
const registry = createRunRegistry({ maxExitedRecords: 2 });
addRunningRecord(registry, { runId: "r1" , sessionId: "s1" , startedAtMs: 1 });
addRunningRecord(registry, { runId: "r2" , sessionId: "s2" , startedAtMs: 2 });
addRunningRecord(registry, { runId: "r3" , sessionId: "s3" , startedAtMs: 3 });
registry.finalize("r1" , { reason: "exit" , exitCode: 0 , exitSignal: null });
registry.finalize("r2" , { reason: "exit" , exitCode: 0 , exitSignal: null });
registry.finalize("r3" , { reason: "exit" , exitCode: 0 , exitSignal: null });
expect(registry.get("r1" )).toBeUndefined();
expect(registry.get("r2" )?.state).toBe("exited" );
expect(registry.get("r3" )?.state).toBe("exited" );
});
it("filters listByScope and returns detached copies" , () => {
const registry = createRunRegistry();
addRunningRecord(registry, {
runId: "r1" ,
sessionId: "s1" ,
scopeKey: "scope:a" ,
startedAtMs: 1 ,
});
addRunningRecord(registry, {
runId: "r2" ,
sessionId: "s2" ,
scopeKey: "scope:b" ,
startedAtMs: 2 ,
});
expect(registry.listByScope(" " )).toEqual([]);
const scoped = registry.listByScope("scope:a" );
expect(scoped).toHaveLength(1 );
const [firstScoped] = scoped;
expect(firstScoped?.runId).toBe("r1" );
if (!firstScoped) {
throw new Error("missing scoped record" );
}
firstScoped.state = "exited" ;
expect(registry.get("r1" )?.state).toBe("running" );
});
});
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland