Sync source failure Agent Activity messages
This commit is contained in:
parent
679c8c198a
commit
00b95667c9
37
src/db.ts
37
src/db.ts
@ -99,6 +99,7 @@ export async function migrate() {
|
||||
body TEXT NOT NULL,
|
||||
related_type TEXT,
|
||||
related_id TEXT,
|
||||
dedupe_key TEXT UNIQUE,
|
||||
acknowledged_at TIMESTAMPTZ,
|
||||
acknowledged_by TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
@ -127,6 +128,8 @@ export async function migrate() {
|
||||
|
||||
await pool.query("ALTER TABLE sources ADD COLUMN IF NOT EXISTS baseline_complete BOOLEAN NOT NULL DEFAULT FALSE");
|
||||
await pool.query("ALTER TABLE signals ADD COLUMN IF NOT EXISTS change_kind TEXT NOT NULL DEFAULT 'new'");
|
||||
await pool.query("ALTER TABLE agent_messages ADD COLUMN IF NOT EXISTS dedupe_key TEXT");
|
||||
await pool.query("CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_messages_dedupe_key ON agent_messages(dedupe_key)");
|
||||
|
||||
const marker = await pool.query(
|
||||
`INSERT INTO app_meta(key,value)
|
||||
@ -525,3 +528,37 @@ export async function acknowledgeAgentMessage(id: string, acknowledgedBy: string
|
||||
);
|
||||
return result.rows[0];
|
||||
}
|
||||
|
||||
export async function postSystemMessageOnce(args: {
|
||||
dedupeKey: string;
|
||||
title: string;
|
||||
body: string;
|
||||
severity?: string;
|
||||
kind?: string;
|
||||
relatedType?: string | null;
|
||||
relatedId?: string | null;
|
||||
}) {
|
||||
const id = randomUUID();
|
||||
const result = await pool.query(
|
||||
`INSERT INTO agent_messages(
|
||||
id,actor_sub,actor_name,actor_client_id,severity,kind,title,body,
|
||||
related_type,related_id,dedupe_key
|
||||
)
|
||||
VALUES($1,'system:source-monitor','Source Monitor','media-intelligence-worker',
|
||||
$2,$3,$4,$5,$6,$7,$8)
|
||||
ON CONFLICT(dedupe_key) DO NOTHING
|
||||
RETURNING *`,
|
||||
[
|
||||
id,
|
||||
args.severity ?? "warning",
|
||||
args.kind ?? "warning",
|
||||
args.title,
|
||||
args.body,
|
||||
args.relatedType ?? null,
|
||||
args.relatedId ?? null,
|
||||
args.dedupeKey
|
||||
]
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
}
|
||||
|
||||
33
src/sync.ts
33
src/sync.ts
@ -1,5 +1,5 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { pool, storeItem } from "./db.js";
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { pool, postSystemMessageOnce, storeItem } from "./db.js";
|
||||
import { fetchSource, SOURCES } from "./sources.js";
|
||||
import { scoreItem } from "./scoring.js";
|
||||
import type { SourceId } from "./types.js";
|
||||
@ -14,12 +14,14 @@ export async function syncSource(sourceId: SourceId) {
|
||||
"INSERT INTO source_runs(id,source_id,status) VALUES($1,$2,'running')",
|
||||
[runId, sourceId]
|
||||
);
|
||||
let previousError: string | null = null;
|
||||
try {
|
||||
const sourceState = await pool.query(
|
||||
"SELECT baseline_complete FROM sources WHERE id=$1",
|
||||
"SELECT baseline_complete,last_error FROM sources WHERE id=$1",
|
||||
[sourceId]
|
||||
);
|
||||
const baseline = !Boolean(sourceState.rows[0]?.baseline_complete);
|
||||
previousError = sourceState.rows[0]?.last_error ?? null;
|
||||
|
||||
const items = await fetchSource(sourceId);
|
||||
let created = 0;
|
||||
@ -43,6 +45,19 @@ export async function syncSource(sourceId: SourceId) {
|
||||
[sourceId, baseline && items.length > 0]
|
||||
);
|
||||
|
||||
if (previousError) {
|
||||
const errorHash = createHash("sha256").update(previousError).digest("hex").slice(0, 16);
|
||||
await postSystemMessageOnce({
|
||||
dedupeKey: `source-recovered:${sourceId}:${errorHash}`,
|
||||
title: `${source.name} recovered`,
|
||||
body: `The source sync is healthy again after the previous error: ${previousError}`,
|
||||
severity: "notice",
|
||||
kind: "update",
|
||||
relatedType: "source",
|
||||
relatedId: sourceId
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
sourceId,
|
||||
mode: baseline ? "baseline" : "live",
|
||||
@ -60,6 +75,18 @@ export async function syncSource(sourceId: SourceId) {
|
||||
"UPDATE sources SET last_synced_at=NOW(),last_error=$2 WHERE id=$1",
|
||||
[sourceId, message]
|
||||
);
|
||||
|
||||
const errorHash = createHash("sha256").update(message).digest("hex").slice(0, 16);
|
||||
await postSystemMessageOnce({
|
||||
dedupeKey: `source-error:${sourceId}:${errorHash}`,
|
||||
title: `${source.name} sync failed`,
|
||||
body: message,
|
||||
severity: "warning",
|
||||
kind: "warning",
|
||||
relatedType: "source",
|
||||
relatedId: sourceId
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user