Cron 定时任务系统

wesgine 定时任务:创建、调度、Actor 边界与执行身份保护。


核心 API

任务管理

方法路径说明
GET/cron任务列表(含 states)
POST/cron添加定时任务
GET/cron/stats调度器统计
DELETE/cron/{id}删除任务
PATCH/cron/{id}更新任务
POST/cron/{id}/trigger立即触发
POST/cron/{id}/enable启用
POST/cron/{id}/disable禁用
GET/cron/{id}/runs运行记录

SDK API

cell.Cron().Add(ctx, job)
cell.Cron().Update(ctx, id, patch)
cell.Cron().Remove(ctx, id)
cell.Cron().Enable(ctx, id)
cell.Cron().Disable(ctx, id)
cell.Cron().Trigger(ctx, id)
cell.Cron().ListAllStates(ctx)
cell.Cron().ListRuns(ctx, id)
cell.Cron().Stats(ctx)

Actor 边界(INV-CRON-10)

Cron 是 Actor 边界的第四个面,泄漏的不是数据而是执行身份。

核心风险

executeJob 把 entry.Actor 抄进 JobRequest,job 以所有者身份跑。

不查主的 Trigger = 以别人的身份跑代码。

两个判据单点

单点用途
jobVisible(actor)可见性(actor == "" 是 admin 视图)
ownedJob(ctx, id, actor)by-ID 解析(行身份 (id, actor))

每个方法都收 actor

wcron.Manager 的每个方法都收 actor 参数。少一个 = 完整越权路径。

错误响应

不存在与不属于你返回同一个 wcron.ErrJobNotFound——不给 ID 探针。


工具侧

cron_manage 工具全 action 取 tc.Actor。

add 不可冒名(jobInput 无 Actor 字段),但 update/remove/trigger 缺 actor 时只需一个 ID 即可越权。


无主 Job

读侧 fail-closed 但 ListDue 不带 actor

无主 job:

「能跑、关不掉、查不到」比「看不到」坏得多。

ClaimOwnerless

Manager.ClaimOwnerless(ctx, actor)

只动 actor = '' 的行。只给单 actor 部署用。

多 actor Cell 盲调 = 把某员工的任务判给另一个人。


种子声明(INV-SEED-01)

CellSpec.Cron 是出生声明,不是常驻状态。

首次 boot → 播种进 wes_cron_jobs
此后 → 存储是唯一权威

标记在探测成功后写,含声明为空。


配额(INV-QUOTA-05)

MaxCronJobs 判据在唯一增长点 cron.Scheduler.Add。

覆盖已有名字 delta=0(upsert 是编辑手势)。


相关文档