import cron, { type ScheduledTask } from "node-cron"; import { backfillAccountProfiles } from "./account-enrichment-service"; import { runScheduledCollections } from "./collection-service"; import { withDatabaseLock } from "./database"; import { resolveCollectionMcpConfig, type CollectionMcpBindings, } from "./mcp-collection-client"; import { ensureSchema, getRawDb } from "./mvp-db"; import { getRuntimeEnv, isEnabled } from "./runtime-env"; import { resolveWecomConfig, type WecomBindings, } from "./wecom-client"; import { runDueSoonWecomNotifications } from "./wecom-notifier-service"; declare global { var __kocLoopScheduler: ScheduledTask | undefined; } async function runDailyJob() { await withDatabaseLock("koc-loop-daily-collection", 0, async () => { await ensureSchema(); const db = getRawDb(); const env = getRuntimeEnv(); const config = resolveCollectionMcpConfig( env as unknown as CollectionMcpBindings, ); const collections = await runScheduledCollections(db, Date.now(), config); const accounts = await backfillAccountProfiles(db, config, 10); let wecom: Awaited> | null = null; if (isEnabled(env.WECOM_NOTIFY_ENABLED, true)) { const wecomConfig = resolveWecomConfig(env as unknown as WecomBindings); if ( wecomConfig.robotWebhook || (wecomConfig.corpId && wecomConfig.agentId && wecomConfig.secret) ) { try { wecom = await runDueSoonWecomNotifications(db, wecomConfig); } catch (error) { console.error("[KOC LOOP] wecom notify failed", error); } } } console.info("[KOC LOOP] daily scheduler completed", { collections, accounts, wecom, }); }); } export function startScheduler() { if (!isEnabled(getRuntimeEnv().ENABLE_SCHEDULER, true)) return; if (globalThis.__kocLoopScheduler) return; globalThis.__kocLoopScheduler = cron.schedule( "0 9 * * *", () => void runDailyJob().catch((error) => { console.error("[KOC LOOP] daily scheduler failed", error); }), { timezone: "Asia/Shanghai", noOverlap: true }, ); console.info("[KOC LOOP] scheduler enabled at 09:00 Asia/Shanghai"); }