import type { ServerContext, ServerModule } from "../types.ts"; import { builtinAgentCheckDefs } from "./agent-checks.ts"; import { registerScheduledJob, scheduleRegistry } from "./registry.ts"; import { registerScheduleRoutes } from "./routes.ts"; import { Scheduler, type SchedulerOptions } from "./scheduler.ts"; export type { JobRunContext, JobRunResult, ScheduledJobDef, ScheduledJobDefaults } from "./registry.ts"; export { registerScheduledJob, scheduleRegistry } from "./registry.ts"; /** * W7-C 定时任务统一注册表 + 看板(docs/runbook/schedules.md): * 各模块 start() 用 registerScheduledJob 登记周期任务;本模块在 io worker 上起唯一调度器(PG 咨询锁)按表驱动, * 并登记内置 Agent 巡检模板(默认关闭)与备份占位。看板 API 见 routes.ts(全部只接受控制台会话)。 * 须放在 SERVER_MODULES 末尾:start 时其它模块已登记完(之后再登记的也会在下一轮同步)。 */ export interface SchedulesModuleOptions { scheduler?: SchedulerOptions; /** 缺省 true;测试可关掉内置巡检 */ builtinChecks?: boolean; } export function createSchedulesModule(opts: SchedulesModuleOptions = {}): ServerModule & { scheduler(): Scheduler | null; } { let scheduler: Scheduler | null = null; return { name: "schedules", scheduler: () => scheduler, registerRoutes(app, ctx) { registerScheduleRoutes(app, ctx, () => scheduleRegistry(ctx)); }, registerTasks() {}, start(ctx: ServerContext) { if (opts.builtinChecks !== false) for (const def of builtinAgentCheckDefs(ctx)) registerScheduledJob(ctx, def); // 备份目前由宿主机 scripts/backup.sh(cron / 手动)执行,这里只占位,看板上显示"未配置" registerScheduledJob(ctx, { key: "maintain.backup", defaults: { name: "备份", description: "数据库与数据目录备份;目前用 umt backup(宿主机 cron 调用),未接入调度", group: "maintain", schedule: { type: "cron", cron: "30 3 * * *" }, enabled: false, available: false, }, run: async () => ({ status: "skipped", summary: "未配置" }), }); scheduler = new Scheduler(ctx, scheduleRegistry(ctx), opts.scheduler); scheduler.start(); }, async stop() { await scheduler?.stop(); scheduler = null; }, }; } export const schedulesModule = createSchedulesModule();