diff --git a/backend-api/__tests__/readinessWarning.test.js b/backend-api/__tests__/readinessWarning.test.js index 8ef0d70..70c68ec 100644 --- a/backend-api/__tests__/readinessWarning.test.js +++ b/backend-api/__tests__/readinessWarning.test.js @@ -1,4 +1,4 @@ -const { buildReadinessWarningDetail, buildReadinessWarningMetadata, buildReadinessWarningState } = require("../../workers/provisioner/readinessWarning"); +const { buildReadinessWarningDetail, buildReadinessWarningMetadata, buildReadinessWarningState, persistReadinessWarning } = require("../../workers/provisioner/readinessWarning"); describe("buildReadinessWarningDetail", () => { it("formats a runtime-only readiness warning", () => { @@ -115,3 +115,53 @@ describe("buildReadinessWarningState", () => { }); }); }); + +describe("persistReadinessWarning", () => { + it("writes warning agent status, warning deployment status, and the runtime warning event in order", async () => { + const db = { query: jest.fn().mockResolvedValue({}) }; + const readiness = { + runtime: { + ok: false, + url: "http://agent.internal:9090/health", + error: "connection refused", + }, + gateway: { ok: true }, + }; + + const result = await persistReadinessWarning(db, { + agentId: "agent-123", + name: "Nora QA", + host: "agent.internal", + readiness, + }); + + expect(db.query).toHaveBeenNthCalledWith( + 1, + "UPDATE agents SET status = 'warning' WHERE id = $1", + ["agent-123"] + ); + expect(db.query).toHaveBeenNthCalledWith( + 2, + "UPDATE deployments SET status = 'warning' WHERE agent_id = $1", + ["agent-123"] + ); + expect(db.query).toHaveBeenNthCalledWith( + 3, + "INSERT INTO events(type, message, metadata) VALUES($1, $2, $3)", + [ + "agent_runtime_warning", + "Agent \"Nora QA\" deployed with readiness warning: runtime unavailable at http://agent.internal:9090/health (connection refused)", + JSON.stringify({ + agentId: "agent-123", + host: "agent.internal", + detail: "runtime unavailable at http://agent.internal:9090/health (connection refused)", + readiness, + }), + ] + ); + expect(result).toEqual(expect.objectContaining({ + agentStatus: "warning", + deploymentStatus: "warning", + })); + }); +}); diff --git a/workers/provisioner/readinessWarning.js b/workers/provisioner/readinessWarning.js index 7150d0f..10da50e 100644 --- a/workers/provisioner/readinessWarning.js +++ b/workers/provisioner/readinessWarning.js @@ -38,4 +38,17 @@ function buildReadinessWarningState({ agentId, name, host, readiness }) { }; } -module.exports = { buildReadinessWarningDetail, buildReadinessWarningMetadata, buildReadinessWarningState }; +async function persistReadinessWarning(db, { agentId, name, host, readiness }) { + const warningState = buildReadinessWarningState({ agentId, name, host, readiness }); + + await db.query(`UPDATE agents SET status = '${warningState.agentStatus}' WHERE id = $1`, [agentId]); + await db.query(`UPDATE deployments SET status = '${warningState.deploymentStatus}' WHERE agent_id = $1`, [agentId]); + await db.query( + "INSERT INTO events(type, message, metadata) VALUES($1, $2, $3)", + [warningState.event.type, warningState.event.message, JSON.stringify(warningState.event.metadata)] + ); + + return warningState; +} + +module.exports = { buildReadinessWarningDetail, buildReadinessWarningMetadata, buildReadinessWarningState, persistReadinessWarning }; diff --git a/workers/provisioner/worker.js b/workers/provisioner/worker.js index a491d8e..a174331 100644 --- a/workers/provisioner/worker.js +++ b/workers/provisioner/worker.js @@ -3,7 +3,7 @@ const IORedis = require('ioredis'); const { Pool } = require('pg'); const { agentRuntimeUrl } = require('../../agent-runtime/lib/contracts'); const { waitForAgentReadiness } = require('./healthChecks'); -const { buildReadinessWarningDetail, buildReadinessWarningState } = require('./readinessWarning'); +const { buildReadinessWarningDetail, persistReadinessWarning } = require('./readinessWarning'); // ── Connections ────────────────────────────────────────── const connection = new IORedis({ @@ -385,14 +385,8 @@ const worker = new Worker('deployments', async (job) => { }); if (!readiness.ok) { const detail = buildReadinessWarningDetail(readiness); - const warningState = buildReadinessWarningState({ agentId: id, name, host, readiness }); console.warn(`[provisioner] Readiness check failed for agent ${id}: ${detail}`); - await db.query(`UPDATE agents SET status = '${warningState.agentStatus}' WHERE id = $1`, [id]); - await db.query(`UPDATE deployments SET status = '${warningState.deploymentStatus}' WHERE agent_id = $1`, [id]); - await db.query( - "INSERT INTO events(type, message, metadata) VALUES($1, $2, $3)", - [warningState.event.type, warningState.event.message, JSON.stringify(warningState.event.metadata)] - ); + await persistReadinessWarning(db, { agentId: id, name, host, readiness }); } // Sync integrations to newly deployed agent container