文件
tennis-training-hub/server/worker.ts
2026-03-15 08:05:37 +08:00

63 行
1.7 KiB
TypeScript

import "dotenv/config";
import { ENV } from "./_core/env";
import * as db from "./db";
import { processBackgroundTask } from "./taskWorker";
const workerId = `app-worker-${process.pid}`;
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function workOnce() {
await db.failExhaustedBackgroundTasks();
await db.requeueStaleBackgroundTasks(new Date(Date.now() - ENV.backgroundTaskStaleMs));
const task = await db.claimNextBackgroundTask(workerId);
if (!task) {
return false;
}
const heartbeatTimer = setInterval(() => {
void db.heartbeatBackgroundTask(task.id, workerId).catch((error) => {
console.error(`[worker] heartbeat failed for ${task.id}:`, error);
});
}, ENV.backgroundTaskHeartbeatMs);
try {
const result = await processBackgroundTask(task);
if (result !== null) {
await db.completeBackgroundTask(task.id, result, "任务执行完成");
}
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown background task error";
await db.failBackgroundTask(task.id, message);
await db.failVisionTestRun(task.id, message);
console.error(`[worker] task ${task.id} failed:`, error);
} finally {
clearInterval(heartbeatTimer);
}
return true;
}
async function main() {
console.log(`[worker] ${workerId} started`);
for (;;) {
try {
const hasWorked = await workOnce();
if (!hasWorked) {
await sleep(ENV.backgroundTaskPollMs);
}
} catch (error) {
console.error("[worker] loop error", error);
await sleep(Math.max(ENV.backgroundTaskPollMs, 3_000));
}
}
}
main().catch((error) => {
console.error("[worker] fatal error", error);
process.exit(1);
});