2026-05-20 10:25:02 +08:00
CREATE TABLE IF NOT EXISTS ops . scheduler_jobs (
job_key VARCHAR ( 96 ) PRIMARY KEY ,
display_name VARCHAR ( 120 ) NOT NULL ,
category VARCHAR ( 64 ) NOT NULL ,
description TEXT ,
enabled BOOLEAN NOT NULL DEFAULT true ,
schedule_type VARCHAR ( 20 ) NOT NULL DEFAULT ' interval ' ,
interval_seconds INT NOT NULL DEFAULT 300 ,
cron_expr VARCHAR ( 120 ) ,
timezone VARCHAR ( 64 ) NOT NULL DEFAULT ' Asia/Shanghai ' ,
timeout_seconds INT NOT NULL DEFAULT 30 ,
batch_size INT ,
max_concurrency INT NOT NULL DEFAULT 1 ,
config JSONB NOT NULL DEFAULT ' {} ' : : jsonb ,
version INT NOT NULL DEFAULT 1 ,
updated_by BIGINT ,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
CHECK ( job_key ~ ' ^[a-z0-9_:-]+$ ' ) ,
CHECK ( schedule_type IN ( ' interval ' , ' cron ' , ' manual ' ) ) ,
CHECK ( interval_seconds > 0 ) ,
CHECK ( timeout_seconds > 0 ) ,
CHECK ( max_concurrency > 0 )
) ;
CREATE INDEX IF NOT EXISTS idx_scheduler_jobs_category
ON ops . scheduler_jobs ( category , job_key ) ;
CREATE TABLE IF NOT EXISTS ops . scheduler_instances (
instance_id VARCHAR ( 160 ) PRIMARY KEY ,
hostname VARCHAR ( 255 ) NOT NULL ,
process VARCHAR ( 80 ) NOT NULL ,
build_version VARCHAR ( 120 ) ,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
metadata JSONB NOT NULL DEFAULT ' {} ' : : jsonb
) ;
CREATE INDEX IF NOT EXISTS idx_scheduler_instances_seen
ON ops . scheduler_instances ( last_seen_at DESC ) ;
CREATE TABLE IF NOT EXISTS ops . scheduler_job_runs (
id BIGSERIAL PRIMARY KEY ,
job_key VARCHAR ( 96 ) NOT NULL REFERENCES ops . scheduler_jobs ( job_key ) ,
trigger_id BIGINT ,
scheduler_instance_id VARCHAR ( 160 ) ,
trigger_type VARCHAR ( 30 ) NOT NULL DEFAULT ' auto ' ,
status VARCHAR ( 30 ) NOT NULL DEFAULT ' running ' ,
config_version INT NOT NULL DEFAULT 1 ,
config_snapshot JSONB NOT NULL DEFAULT ' {} ' : : jsonb ,
stats JSONB NOT NULL DEFAULT ' {} ' : : jsonb ,
error_message TEXT ,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
finished_at TIMESTAMPTZ ,
duration_ms BIGINT ,
CHECK ( trigger_type IN ( ' auto ' , ' manual ' , ' dry_run ' ) ) ,
CHECK ( status IN ( ' running ' , ' success ' , ' failed ' , ' skipped ' ) )
) ;
CREATE INDEX IF NOT EXISTS idx_scheduler_job_runs_job_started
ON ops . scheduler_job_runs ( job_key , started_at DESC , id DESC ) ;
CREATE INDEX IF NOT EXISTS idx_scheduler_job_runs_status_started
ON ops . scheduler_job_runs ( status , started_at DESC ) ;
2026-05-20 12:19:27 +08:00
CREATE INDEX IF NOT EXISTS idx_scheduler_job_runs_auto_started
ON ops . scheduler_job_runs ( job_key , started_at DESC , id DESC )
WHERE trigger_type = ' auto ' ;
2026-05-20 10:25:02 +08:00
CREATE TABLE IF NOT EXISTS ops . scheduler_job_triggers (
id BIGSERIAL PRIMARY KEY ,
job_key VARCHAR ( 96 ) NOT NULL REFERENCES ops . scheduler_jobs ( job_key ) ,
trigger_type VARCHAR ( 30 ) NOT NULL DEFAULT ' manual ' ,
status VARCHAR ( 30 ) NOT NULL DEFAULT ' pending ' ,
requested_by BIGINT ,
reason TEXT ,
config_override JSONB NOT NULL DEFAULT ' {} ' : : jsonb ,
scheduler_instance_id VARCHAR ( 160 ) ,
run_id BIGINT REFERENCES ops . scheduler_job_runs ( id ) ,
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW ( ) ,
claimed_at TIMESTAMPTZ ,
finished_at TIMESTAMPTZ ,
error_message TEXT ,
CHECK ( trigger_type IN ( ' manual ' , ' dry_run ' ) ) ,
CHECK ( status IN ( ' pending ' , ' claimed ' , ' success ' , ' failed ' , ' skipped ' ) )
) ;
CREATE INDEX IF NOT EXISTS idx_scheduler_job_triggers_pending
ON ops . scheduler_job_triggers ( job_key , requested_at ASC , id ASC )
WHERE status = ' pending ' ;
INSERT INTO ops . scheduler_jobs
( job_key , display_name , category , description , enabled , schedule_type , interval_seconds , timezone , timeout_seconds , batch_size , config )
VALUES
2026-05-20 12:19:27 +08:00
( ' schedule_dispatch ' , ' 内容定时任务派发 ' , ' content ' , ' 索引驱动的延迟队列派发,仅认领到期内容任务并投递生成队列。 ' , true , ' interval ' , 15 , ' Asia/Shanghai ' , 30 , 100 , ' {} ' : : jsonb ) ,
( ' monitoring_daily_task ' , ' AI 监控每日任务生成 ' , ' monitoring ' , ' 按业务日小批量物化监控采集任务并派发到桌面任务队列。 ' , true , ' interval ' , 300 , ' Asia/Shanghai ' , 45 , 64 , ' {"max_materialize_per_plan":12,"max_materialize_per_brand":4} ' : : jsonb ) ,
( ' monitoring_result_recovery ' , ' 监控结果恢复 ' , ' monitoring ' , ' 按回调结果队列索引恢复未成功入队的监控结果。 ' , true , ' interval ' , 60 , ' Asia/Shanghai ' , 30 , 100 , ' {} ' : : jsonb ) ,
( ' monitoring_lease_recovery ' , ' 监控租约回收 ' , ' monitoring ' , ' 按过期租约索引限批回收超过租约时间仍未回调的监控任务。 ' , true , ' interval ' , 1800 , ' Asia/Shanghai ' , 30 , 1000 , ' {} ' : : jsonb ) ,
( ' monitoring_received_inspection ' , ' 监控 received 卡死检查 ' , ' monitoring ' , ' 按 received watchdog 索引限批标记长时间未入队的监控任务。 ' , true , ' interval ' , 300 , ' Asia/Shanghai ' , 30 , 100 , ' {"threshold":"15m"} ' : : jsonb ) ,
( ' generation_state_check ' , ' 生成任务状态巡检 ' , ' generation ' , ' 低频、限批检查文章生成任务与文章状态一致性。 ' , true , ' interval ' , 300 , ' Asia/Shanghai ' , 10 , 100 , ' {"lookback":"24h"} ' : : jsonb ) ,
( ' monitoring_retention_cleanup ' , ' 监控历史保留清理 ' , ' monitoring ' , ' 按保留窗口和索引限批删除最近 30 天以前的监控历史数据。 ' , true , ' interval ' , 86400 , ' Asia/Shanghai ' , 900 , 5000 ,
2026-05-20 10:25:02 +08:00
' {"retention_days":30,"batch_size":5000,"max_batches_per_run":200,"dry_run":false,"statement_timeout":"5s","run_at_local":"02:30"} ' : : jsonb )
ON CONFLICT ( job_key ) DO UPDATE
SET display_name = EXCLUDED . display_name ,
category = EXCLUDED . category ,
description = EXCLUDED . description ,
2026-05-20 12:19:27 +08:00
config = ops . scheduler_jobs . config | | EXCLUDED . config ,
2026-05-20 10:25:02 +08:00
updated_at = NOW ( ) ;