import type { Kysely } from "kysely"; import { dropTables, execDdl, oneOf } from "../src/migration-helpers.ts"; // W9-I 进程与健康:各常驻进程(api / worker / worker:agent / all)每 15s upsert 一行心跳, // 同时追加一条采样到 process_heartbeat_sample 供 GET /system/health/history 画图(保留 7 天,写入方顺手裁剪)。 // instance_id = :::同一容器重启覆盖旧行,不会越积越多;超过 45s 没心跳由读取方标 stale。 // 另给 task.engine_run_id 补索引:引擎 runs 列表按业务字段筛选时按 run id 反查业务任务行。 // biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型 export async function up(db: Kysely): Promise { await execDdl( db, ` create table process_heartbeat ( instance_id text primary key, process_kind text not null ${oneOf("process_kind", ["api", "worker", "worker:agent", "all"])}, pid integer not null, host text not null, version text not null, started_at timestamptz not null, last_beat_at timestamptz not null default now(), event_loop_lag_ms integer not null default 0 check (event_loop_lag_ms >= 0), event_loop_lag_max_ms integer not null default 0 check (event_loop_lag_max_ms >= 0), concurrency jsonb not null default '{}'::jsonb, running_runs integer check (running_runs is null or running_runs >= 0), extra jsonb not null default '{}'::jsonb ); create index process_heartbeat_beat_idx on process_heartbeat (last_beat_at); create table process_heartbeat_sample ( id bigserial primary key, instance_id text not null, process_kind text not null, at timestamptz not null default now(), event_loop_lag_ms integer not null default 0, event_loop_lag_max_ms integer not null default 0, running_runs integer, sse_connections integer ); create index process_heartbeat_sample_at_idx on process_heartbeat_sample (at, instance_id); create index if not exists task_engine_run_idx on task (engine_run_id) where engine_run_id is not null; `, ); } // biome-ignore lint/suspicious/noExplicitAny: 同上 export async function down(db: Kysely): Promise { await execDdl( db, `drop index if exists task_engine_run_idx; ${dropTables(["process_heartbeat_sample", "process_heartbeat"])}`, ); }