import { db } from "@tasks/database"; import IoRedis from "ioredis"; import { detectStalledConvoys } from "./db/convoy.js"; import { loadEnv } from "./env.js"; import { runOrchestratorTick } from "./tick.js"; async function main(): Promise { const env = loadEnv(); const redis = env.REDIS_URL ? new IoRedis(env.REDIS_URL) : null; if (env.ORCHESTRATOR_DRY_RUN) { console.info("[orchestrator] DRY-RUN mode — jobs will be logged, not enqueued"); } else if (!redis) { console.warn("[orchestrator] REDIS_URL not set — running in DRY-RUN mode"); } console.info(`[orchestrator] polling every ${env.ORCHESTRATOR_POLL_MS}ms`); const loop = async () => { try { const results = await runOrchestratorTick(db, redis, { ...env, ORCHESTRATOR_DRY_RUN: env.ORCHESTRATOR_DRY_RUN || !redis, }); const stalled = await detectStalledConvoys(db, env.ORCHESTRATOR_STALL_MINUTES); if (stalled.length > 0) { console.warn( `[orchestrator] stall detector: ${stalled.length} open agent_runs older than ${env.ORCHESTRATOR_STALL_MINUTES}m`, ); } if (results.length === 0) { console.info("[orchestrator] no active convoys"); } } catch (error) { console.error("[orchestrator] tick failed:", error); } }; await loop(); setInterval(loop, env.ORCHESTRATOR_POLL_MS); } main().catch((error) => { console.error("[orchestrator] fatal:", error); process.exit(1); });