fix: recover run runtime state and logs

This commit is contained in:
npc0-hue
2026-08-07 12:01:26 +08:00
parent 3818fa0344
commit b789925ae5
23 changed files with 297 additions and 78 deletions
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { canStartServer, canStopServer } from "./serverManagement";
import type { ServerInstanceState } from "../api/types";
import { canStartServer, canStopServer, runtimeObservationFreshness } from "./serverManagement";
import type { RunEndpointResponse, ServerInstanceResponse, ServerInstanceState } from "../api/types";
describe("server management lifecycle contracts", () => {
it("allows explicit starts from recoverable non-running states", () => {
@@ -16,4 +16,12 @@ describe("server management lifecycle contracts", () => {
expect(canStopServer("running")).toBe(true);
expect(canStopServer("failed")).toBe(false);
});
it("distinguishes a fresh Run observation from an unverified historical lifecycle state", () => {
const instance = { id: "server-1", state: "running", runEndpointId: "run-1" } as ServerInstanceResponse;
const endpoint = { id: "run-1", status: "online", lastHeartbeatAt: "2026-08-07T10:00:00Z" } as RunEndpointResponse;
expect(runtimeObservationFreshness(instance, endpoint, Date.parse("2026-08-07T10:00:30Z"))).toBe("fresh");
expect(runtimeObservationFreshness(instance, endpoint, Date.parse("2026-08-07T10:01:00Z"))).toBe("unverified");
expect(runtimeObservationFreshness(instance, { ...endpoint, status: "offline" }, Date.parse("2026-08-07T10:00:01Z"))).toBe("unverified");
});
});
@@ -61,6 +61,14 @@ export interface ServerManagementSummary {
failed: number;
}
export type RuntimeObservationFreshness = "fresh" | "unverified";
export function runtimeObservationFreshness(instance: ServerInstanceResponse, endpoint: RunEndpointResponse | undefined, now = Date.now()): RuntimeObservationFreshness {
if (!endpoint || endpoint.status !== "online") return "unverified";
const heartbeat = Date.parse(endpoint.lastHeartbeatAt);
return Number.isFinite(heartbeat) && now-heartbeat <= 45_000 ? "fresh" : "unverified";
}
export const emptyServerCreateForm: ServerCreateFormState = {
id: "",
name: "",
+4 -3
View File
@@ -1,4 +1,4 @@
import type { JobResponse, ServerInstanceResponse, ServerMetricsResponse, UserContactProfile, UserStatus, UserThemePreferenceResponse } from "../api/types";
import type { JobResponse, RunEndpointResponse, ServerInstanceResponse, ServerMetricsResponse, UserContactProfile, UserStatus, UserThemePreferenceResponse } from "../api/types";
export type WorkspaceRole = "platformAdmin" | "serverOwner" | "serverAdmin";
@@ -89,8 +89,9 @@ export interface OperationRecord {
}
export interface ServerCardView {
instance: ServerInstanceResponse;
metrics?: ServerMetricsResponse;
instance: ServerInstanceResponse;
endpoint?: RunEndpointResponse;
metrics?: ServerMetricsResponse;
pendingJobs: number;
activeJobs?: number;
failedJobs?: number;