fix(cloud-api): keep health live nonblocking (#1808)
Route /health/live through cached runtime summary so DB durable retry cannot block liveness probes. Keep /health as the full durable readiness endpoint.\n\nRefs #1807.
This commit is contained in:
@@ -262,20 +262,24 @@ function ensurePreinstalledHwpodSpec({ workspace }) {
|
||||
export async function buildHealthPayload(options = {}) {
|
||||
const serviceId = CLOUD_API_SERVICE_ID;
|
||||
const env = options.env ?? process.env;
|
||||
const healthMode = options.healthMode === "live" ? "live" : "readiness";
|
||||
const liveProbe = healthMode === "live";
|
||||
ensureCodeAgentRuntimeBase(env);
|
||||
const metadata = buildMetadataFromEnv(env, {
|
||||
serviceId,
|
||||
fallbackImageRepository: "ghcr.io/pikastech/hwlab-cloud-api"
|
||||
});
|
||||
const dbProbe = await buildDbRuntimeReadiness(env, options.dbProbe);
|
||||
const runtimeStore = options.runtimeStore ?? createConfiguredCloudRuntimeStore({ ...options, env });
|
||||
const dbProbe = await buildDbRuntimeReadiness(env, liveProbe ? { ...(options.dbProbe ?? {}), probe: false } : options.dbProbe);
|
||||
const codeAgent = await describeCodeAgentAvailability(env, options);
|
||||
const runtime = await runtimeReadiness(options.runtimeStore ?? createConfiguredCloudRuntimeStore({ ...options, env }));
|
||||
const runtime = liveProbe ? runtimeReadinessSnapshot(runtimeStore) : await runtimeReadiness(runtimeStore);
|
||||
const db = applyRuntimeDbReadinessLayers(dbProbe, runtime);
|
||||
const readiness = buildCloudApiReadiness({ db, codeAgent, runtime });
|
||||
|
||||
return {
|
||||
serviceId,
|
||||
environment: runtimeEnvironment(env),
|
||||
healthMode,
|
||||
status: readiness.status,
|
||||
ready: readiness.ready,
|
||||
revision: metadata.revision,
|
||||
@@ -300,11 +304,54 @@ export async function buildHealthPayload(options = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeReadinessSnapshot(runtimeStore) {
|
||||
if (runtimeStore && typeof runtimeStore.summary === "function") {
|
||||
try {
|
||||
const summary = runtimeStore.summary();
|
||||
return {
|
||||
...summary,
|
||||
readinessFresh: false,
|
||||
readinessSource: "cached-summary"
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
adapter: "unknown",
|
||||
durable: false,
|
||||
ready: false,
|
||||
status: "degraded",
|
||||
blocker: "runtime_readiness_snapshot_failed",
|
||||
reason: error instanceof Error ? error.message : "Runtime readiness snapshot failed",
|
||||
readinessFresh: false,
|
||||
readinessSource: "cached-summary",
|
||||
valuesRedacted: true,
|
||||
endpointRedacted: true
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
adapter: "unknown",
|
||||
durable: false,
|
||||
ready: false,
|
||||
status: "degraded",
|
||||
blocker: "runtime_readiness_snapshot_unavailable",
|
||||
reason: "Runtime store does not expose a cached summary for /health/live",
|
||||
readinessFresh: false,
|
||||
readinessSource: "cached-summary",
|
||||
valuesRedacted: true,
|
||||
endpointRedacted: true
|
||||
};
|
||||
}
|
||||
|
||||
async function routeRequest(request, response, options) {
|
||||
const url = new URL(request.url || "/", "http://hwlab-cloud-api.local");
|
||||
|
||||
if (request.method === "GET" && (url.pathname === "/health" || url.pathname === "/health/live")) {
|
||||
sendJson(response, 200, await buildHealthPayload(options));
|
||||
if (request.method === "GET" && url.pathname === "/health/live") {
|
||||
sendJson(response, 200, await buildHealthPayload({ ...options, healthMode: "live" }));
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method === "GET" && url.pathname === "/health") {
|
||||
sendJson(response, 200, await buildHealthPayload({ ...options, healthMode: "readiness" }));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user