diff --git a/src/components/microservices/decision-center/src/index.ts b/src/components/microservices/decision-center/src/index.ts index b222d5da..3fda8d9f 100644 --- a/src/components/microservices/decision-center/src/index.ts +++ b/src/components/microservices/decision-center/src/index.ts @@ -71,6 +71,8 @@ const serviceStartedAt = new Date().toISOString(); const recentLogs: JsonRecord[] = []; let schemaReady = false; let schemaLastError: JsonRecord | null = null; +let databaseHealth: JsonRecord = { ok: false, recordCount: 0, checkedAt: "", error: null }; +let databaseHealthRefreshInFlight = false; function envString(name: string, fallback: string): string { const value = process.env[name]; @@ -292,6 +294,29 @@ async function waitForSchema(): Promise { throw new Error(`Decision Center schema initialization failed: ${JSON.stringify(schemaLastError)}`); } +async function refreshDatabaseHealth(): Promise { + if (databaseHealthRefreshInFlight) return; + databaseHealthRefreshInFlight = true; + try { + const rows = await sql<{ count: string | number }[]>`SELECT count(*) AS count FROM decision_center_records`; + databaseHealth = { + ok: true, + recordCount: Number(rows[0]?.count ?? 0), + checkedAt: new Date().toISOString(), + error: null, + }; + } catch (error) { + databaseHealth = { + ok: false, + recordCount: 0, + checkedAt: new Date().toISOString(), + error: errorToJson(error), + }; + } finally { + databaseHealthRefreshInFlight = false; + } +} + function deployInfo(): JsonRecord { return { serviceId: envString("UNIDESK_DEPLOY_SERVICE_ID", "decision-center"), @@ -301,17 +326,8 @@ function deployInfo(): JsonRecord { }; } -async function health(): Promise { - let dbOk = false; - let recordCount = 0; - let dbError: JsonValue = null; - try { - const rows = await sql<{ count: string | number }[]>`SELECT count(*) AS count FROM decision_center_records`; - dbOk = true; - recordCount = Number(rows[0]?.count ?? 0); - } catch (error) { - dbError = errorToJson(error); - } +function health(): JsonRecord { + const dbOk = databaseHealth.ok === true; return { ok: schemaReady && dbOk, service: "decision-center", @@ -319,8 +335,8 @@ async function health(): Promise { startedAt: serviceStartedAt, storage: "postgres", schemaReady, - recordCount, - database: { ok: dbOk, error: dbError }, + recordCount: Number(databaseHealth.recordCount ?? 0), + database: databaseHealth, deploy: deployInfo(), }; } @@ -473,7 +489,7 @@ async function route(req: Request): Promise { return jsonResponse({ ok: true, service: "decision-center", status: "alive", startedAt: serviceStartedAt, deploy: deployInfo() }); } if (url.pathname === "/health") { - const body = await health(); + const body = health(); return jsonResponse(body, body.ok === true ? 200 : 503); } if (url.pathname === "/logs" && method === "GET") return jsonResponse({ ok: true, logs: recentLogs.slice(-200) }); @@ -504,7 +520,12 @@ Bun.serve({ }, }); -void waitForSchema().catch((error) => { - log("error", "schema_init_failed", { error: errorToJson(error) }); -}); +void waitForSchema() + .then(() => refreshDatabaseHealth()) + .catch((error) => { + log("error", "schema_init_failed", { error: errorToJson(error) }); + }); +setInterval(() => { + if (schemaReady) void refreshDatabaseHealth(); +}, 15_000).unref(); log("info", "service_started", { host: config.host, port: config.port, storage: "postgres" });