- 0028_scheduled_jobs: scheduled_job (stable key, group, kind task|agent_check, enabled/schedule with defaults + customized flag, config, last_* / next_run_at / run_requested_at / running_since, counters) and scheduled_job_run history - contracts/schedules.ts: ScheduleSpec (interval | 5-field cron), AgentCheckConfig (goal template, capability allowlist, budget, trigger condition, allowRecover, reportAsDecision), board / run views - Api.schedules: list, create (agent_check only), update, remove, run-now, skip, runs; all admin + console session only Co-Authored-By: Claude Opus 5.5 <[email protected]>
74 lines
3.0 KiB
TypeScript
74 lines
3.0 KiB
TypeScript
import type { Kysely } from "kysely";
|
|
import { dropTables, execDdl, oneOf } from "../src/migration-helpers.ts";
|
|
|
|
// W7-C 定时任务统一注册表(docs/runbook/schedules.md):
|
|
// - scheduled_job:稳定 key 为主键(如 feeds.poll);模块启动时登记默认值(customized 后不覆盖 enabled/schedule);
|
|
// io worker 上持有咨询锁的调度器按 next_run_at / run_requested_at 触发,结果写回 last_* 与计数。
|
|
// kind=agent_check 为 Agent 巡检(config 存目标模板/能力白名单/预算/触发条件),builtin=false 为用户自定义。
|
|
// - scheduled_job_run:运行历史,每个任务只保留最近若干条(调度器写入时裁剪);巡检入队的 agent_run 结束后
|
|
// 调度器回填 agent_status 与 summary。
|
|
|
|
const GROUPS = ["collect", "download", "organize", "maintain", "agent"] as const;
|
|
const KINDS = ["task", "agent_check"] as const;
|
|
const STATUSES = ["ok", "failed", "skipped", "running"] as const;
|
|
const TRIGGERS = ["schedule", "manual", "skip"] as const;
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
|
|
export async function up(db: Kysely<any>): Promise<void> {
|
|
await execDdl(
|
|
db,
|
|
`
|
|
create table scheduled_job (
|
|
id text primary key,
|
|
name text not null,
|
|
description text,
|
|
board_group text not null ${oneOf("board_group", GROUPS)},
|
|
kind text not null ${oneOf("kind", KINDS)},
|
|
builtin boolean not null default true,
|
|
available boolean not null default true,
|
|
enabled boolean not null,
|
|
default_enabled boolean not null,
|
|
schedule jsonb not null,
|
|
default_schedule jsonb not null,
|
|
customized boolean not null default false,
|
|
config jsonb not null default '{}'::jsonb,
|
|
last_run_at timestamptz,
|
|
last_status text ${oneOf("last_status", STATUSES)},
|
|
last_duration_ms integer,
|
|
last_error text,
|
|
next_run_at timestamptz,
|
|
run_requested_at timestamptz,
|
|
running_since timestamptz,
|
|
run_count integer not null default 0,
|
|
fail_count integer not null default 0,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now()
|
|
);
|
|
create trigger scheduled_job_touch_updated_at before update on scheduled_job
|
|
for each row execute function umt_touch_updated_at();
|
|
create index scheduled_job_due_idx on scheduled_job (next_run_at) where enabled;
|
|
|
|
create table scheduled_job_run (
|
|
id uuid primary key default gen_random_uuid(),
|
|
job_id text not null references scheduled_job (id) on delete cascade,
|
|
trigger text not null ${oneOf("trigger", TRIGGERS)},
|
|
status text not null ${oneOf("status", STATUSES)},
|
|
started_at timestamptz not null default now(),
|
|
finished_at timestamptz,
|
|
duration_ms integer,
|
|
error text,
|
|
summary text,
|
|
agent_run_id uuid references agent_run (id) on delete set null,
|
|
agent_status text,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
create index scheduled_job_run_job_idx on scheduled_job_run (job_id, started_at desc);
|
|
`,
|
|
);
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: 同上
|
|
export async function down(db: Kysely<any>): Promise<void> {
|
|
await execDdl(db, dropTables(["scheduled_job_run", "scheduled_job"]));
|
|
}
|