feat(server): readiness 与作业统计可观测性(E11)
- 新增 /ready(DB 探活失败返回 503) - OCR 作业输出 claimed/available/duplicate/failed 统计 - README 补充 /health 与 /ready 说明
这个提交包含在:
+25
-5
@@ -249,28 +249,39 @@ async function processClaimedInvoice(prisma, config, claimedInvoice, workerId, l
|
||||
},
|
||||
"OCR invoice marked as duplicate",
|
||||
);
|
||||
return;
|
||||
return { outcome: "duplicate" };
|
||||
}
|
||||
|
||||
await markInvoiceAsAvailable(prisma, claimedInvoice.id, normalized, ocrResultId);
|
||||
return { outcome: "available" };
|
||||
} catch (error) {
|
||||
const message = trimErrorMessage(error);
|
||||
await markInvoiceAsFailed(prisma, claimedInvoice, message, config);
|
||||
logger.error({ err: error, invoiceId: claimedInvoice.id, workerId }, "OCR processing failed");
|
||||
return { outcome: "failed" };
|
||||
}
|
||||
}
|
||||
|
||||
async function runOcrOnce(prisma, config, logger, workerId = `ocr:${process.pid}`) {
|
||||
const claimed = await claimPendingInvoices(prisma, config, workerId);
|
||||
if (!claimed.length) {
|
||||
return { claimed: 0 };
|
||||
return { claimed: 0, available: 0, duplicate: 0, failed: 0 };
|
||||
}
|
||||
|
||||
const stats = { claimed: claimed.length, available: 0, duplicate: 0, failed: 0 };
|
||||
|
||||
for (const item of claimed) {
|
||||
await processClaimedInvoice(prisma, config, item, workerId, logger);
|
||||
const result = await processClaimedInvoice(prisma, config, item, workerId, logger);
|
||||
if (result?.outcome === "available") {
|
||||
stats.available += 1;
|
||||
} else if (result?.outcome === "duplicate") {
|
||||
stats.duplicate += 1;
|
||||
} else if (result?.outcome === "failed") {
|
||||
stats.failed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return { claimed: claimed.length };
|
||||
return stats;
|
||||
}
|
||||
|
||||
function startOcrJob(fastify) {
|
||||
@@ -289,7 +300,16 @@ function startOcrJob(fastify) {
|
||||
|
||||
running = true;
|
||||
try {
|
||||
await runOcrOnce(fastify.prisma, fastify.config, fastify.log, workerId);
|
||||
const result = await runOcrOnce(fastify.prisma, fastify.config, fastify.log, workerId);
|
||||
if (result.claimed > 0) {
|
||||
fastify.log.info(
|
||||
{
|
||||
workerId,
|
||||
...result,
|
||||
},
|
||||
"OCR job tick processed",
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
fastify.log.error({ err: error }, "OCR job tick failed");
|
||||
} finally {
|
||||
|
||||
在新工单中引用
屏蔽一个用户