定时调度与触发器

适用版本:ChengOS v0.1.0+ | 最后核对:2026-08-12 | 来源:crates/cheng-core/src/domain/scheduled_task.rscrates/cheng-core/src/services/tiered_scheduler.rscrates/cheng-nodes/src/nodes/builtin/tools/schedule.rscrates/cheng-api/src/rest/handlers/schedule/mod.rs

工作流有四种启动方式:用户手动运行、渠道消息到达、另一个工作流把它当子流程调用,或者时钟到点。本页讲时钟。

分层调度器

ChengOS 的定时不是一个 cron 进程,而是一个分层调度器,其设计目标是在多节点和进程重启下依然正确:

      遥远的未来                    即将到来               马上就到
  ┌──────────────────┐      ┌──────────────────┐      ┌──────────────────┐
  │   PostgreSQL     │ ───► │   Redis(温层)  │ ───► │  热轮             │
  │  (唯一真相)     │      │  warm_window     │      │  DelayQueue      │
  │                  │      │  默认 300 秒     │      │  默认 60 秒       │
  └──────────────────┘      └──────────────────┘      └──────────────────┘
          ▲                                                    │
          │           PG 清扫器把滞留任务重新入队               ▼
          └──────────────────────────────────────────    执行工作流

PostgreSQL 是唯一真相。Redis 承载温层窗口,并提供分布式执行锁。热轮是一个进程内的 DelayQueue,只装即将触发的任务。

任务 id 是 i64(PostgreSQL BIGSERIAL)而不是 UUID,正是为了能直接用作 DelayQueue 的键。

配置

设置 默认 开发 生产
hot_window_secs 60 10 60
warm_window_secs 300 60 300
load_batch_size 100 20 500
sweeper_interval_secs 30 10 30
stale_threshold_secs 30 15 30
lock_timeout_secs 60 30 120
max_concurrency 16 4 64
heartbeat_interval_secs 5 3 5
execution_timeout_secs 300 60 300
crash_recovery_interval_secs 60 20 60

warm_window_secs 必须大于等于 hot_window_secs;配置会校验这一点,而不是留下一个能让任务掉进去的缝隙。

可靠性

三套机制,各自覆盖一类故障:

  • PG 清扫器把逾期超过 stale_threshold_secs 的任务重新入队——覆盖 Redis 条目丢失。
  • 节点心跳heartbeat_interval_secs 一次;沉默超过 node_stale_threshold_secs 的节点被判定为死亡。
  • 崩溃恢复(仅 Leader 执行)找出卡在 running 且超过 execution_timeout_secs 的任务,或重试或永久判失败。

认领任务使用乐观锁;冲突的认领会以锁冲突失败,而不是重复执行。

任务生命周期

 ┌─────────┐   claim()    ┌─────────┐
 │ Pending │ ──────────►  │ Running │
 └─────────┘              └─────────┘
      ▲                        │
      │ schedule_retry()  ┌────┴──────────────┐
      │                   ▼                   ▼
      │              ┌──────────┐        ┌────────┐
      └──────────────│ Pending  │        │ Failed │ (超过最大重试)
                     └──────────┘        └────────┘
                       另有:Completed、Cancelled、Paused

成功完成的周期性任务会被自动重新排到下一个 cron 时间;一次性任务在 completed 处结束。

周期规则与时区

{ "timezone": "Asia/Shanghai", "cron": "0 8 * * *" }

timezone 是 IANA 标识符,对周期性任务是必填的。它不是装饰:调度器需要它才能在夏令时切换时正确算出下一次触发。「每天 08:00」在夏天和冬天对应不同的 UTC 时刻,只用 UTC 的 cron 每年会错两次。

载荷还携带 params(交给工作流)、可选的 label,以及创建该定时任务的 user_id / tenant_id / workspace_id 作用域。

定时节点

tools/schedule 让你在工作流内部管理定时任务——包括从智能体里管理,这正是「每天早上提醒我」能以对话方式实现的原因。

动作list_tasksget_taskget_execution_resultcreate_taskupdate_taskpause_taskresume_taskcancel_taskdelete_task

模式manual(用户填参数)或 llm(模型填参数)。

run_at 接受三种格式

格式 例子 结果
相对延迟 2m30m1h1d 等待之后运行一次
cron 表达式 0 9 * * *0 9 * * 10 9 * * 0,6 周期运行
本地墙钟时间 2026-06-30T09:00 在该时刻运行一次

日期时间格式不带时区也不带偏移——节点自己套用服务器时区。一次性日期时间必须在未来,如果不是,校验错误会报出当前服务器时间,让调用方据此纠正。这个细节的存在是因为:一个被要求安排日程的模型,否则会去猜今天是几号,然后猜错。

timezone 被刻意设为不可由 LLM 填写的字段:节点自动使用宿主的系统时区,于是用户只需说出墙钟时间,模型永远不必去挑时区。它仍作为可选的手动覆盖项,供界面和其他非 LLM 调用方使用。

frequency 是比裸 cron 更友好的替代:onceevery_minutehourlydailyweeklymonthly,或 customcustom_cron

输入与名称——务必避开的错误

有三个字段很容易混淆:

字段 不是
task_text 工作流的输入,纯文本——对以对话打头的工作流会成为 raw_input 名称
params 显式的输入对象,如 {"raw_input": "hello"}——恰是入口节点收到的东西 名称
label 在列表与日志中显示的简短描述性名称 任务内容

内容用 task_text params。务必设置 label,控制在 20 字以内并写得有描述性——一份全是 任务1test123 的任务列表,会逼你按 id 逐个查询才能找到目标。

其他选项:priority(默认 0)、max_retries(默认 3)、用于把 task_text 路由到特定入口节点的 target_node_id,以及 list_tasks 用的 limit(默认 50,最大 500)/offsetstatus

REST 接口

GET|POST         /schedules                 列出、创建
GET              /schedules/metrics         调度器指标
GET|PATCH|DELETE /schedules/:id             获取、更新、取消(软)
GET              /schedules/:id/executions  该任务的执行历史
DELETE           /schedules/:id/hard        硬删除
POST             /schedules/:id/pause
POST             /schedules/:id/resume

DELETE /schedules/:id 是取消,/hard 才删除记录行。cron 表达式在创建和更新时校验——非法表达式在那时就被拒绝,而不是等到下一次滴答才悄悄失败。

选择模式

你想要 这样做
今天晚些时候跑一次 run_at: "2h" 或一个本地日期时间
每天早上 09:00 run_at: "0 9 * * *" 并带上时区
用户在对话里创建的提醒 一个挂了 tools/schedule、模式为 llm 的智能体
周期性重建索引 一个指向你索引工作流的定时任务——按版本幂等
对外部事件做出反应 那不是定时任务——用渠道

下一步

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容