定时任务:没人推代码也要跑
第 13 篇把定时任务当成一种触发方式带过。这篇展开——因为它的坑比 push 多得多。
一、写法:分支名 + cron 表达式
main:
"crontab: 30 5,17 * * *":
- name: nightly-build-and-test
stages:
- name: run-tests
script: echo "Running scheduled tasks..."
外层键名 main 是执行时用的分支,任务触发就拉这个分支 HEAD 的代码。
内层 crontab: <表达式> 是触发时机,标准 POSIX cron,时区 Asia/Shanghai。
上面这条的意思是:每天 5:30 和 17:30 各跑一次。
二、和 push 事件的四处差异
| 特性 | 定时任务 | push 事件 |
|---|---|---|
| 分支 | 只能写单一明确分支 | 支持 glob |
| 执行身份 | 最后修改该配置的人 | 执行 push 的人 |
| 最小间隔 | 5 分钟 | 无限制 |
| 删除 | 移除 crontab: 条目 | 移除 push: 条目 |
第一条最反直觉:想给 feature/* 都排夜间构建,做不到。要么写死 feature/main-dev 这种单分支,要么让流水线自己遍历。
第二条最危险,下面单独说。
三、执行身份是个活人,这是最大的坑
定时任务触发时,流水线的执行身份是最后添加或修改这段 crontab 配置、并推送到仓库的那个人。
由此推出一串连带后果:
- 那个人被移出仓库 → 他名下的定时任务全部失败
- 那个人离职账号停用 → 同上
- 换人改了一下配置并推送 → 负责人就换成新的人
所以团队里应该有个约定:定时任务配置由常驻负责人维护。别让实习生随手改一版推上去。
:::tip 修不动的定时任务 如果报「执行失败」但不是代码问题,先想是不是负责人已经不在了。 有权限的人改一行配置再推一次,负责人就更新了。 :::
四、CNB_TOKEN 只能碰当前仓库
定时任务的 CNB_TOKEN 以负责人身份签发,但访问范围默认限定在当前仓库。
原因很直白:定时任务是「无人值守 + 长期运行」,权限放太宽,一旦配置文件被改成恶意内容,就是长期后门。
需要定时任务在根组织内跨仓操作(比如聚合几个仓库的构建产物),
得由根组织管理员去 组织设置 → 云原生构建管控 打开「允许定时任务跨仓操作」。
打开后范围扩到根组织,仍然不能跨根组织。
真要跨根组织,用 API 触发:外部调度器持专用令牌调 OpenAPI 按需触发目标仓库,权限边界清楚得多。
五、间隔限制与时间选择
最小间隔 5 分钟。写 * * * * * 根本提交不上去——提交时就报错,不是运行时才失败。
夜间构建的时间别都堆在 0 点。如果你的 cron 是 0 2 * * *,提示两点没跑,多半是这个时段排队。
六、改动不会自动同步的两种情况
如果 .cnb.yml 用 include 引入了模板(比如 crontab.yml),同步机制是这样的:
只有当 .cnb.yml 本身发生变更的推送,才会重新解析定时任务。
于是这两种情况会失灵:
- 只改
crontab.yml,没动.cnb.yml→ 新增的任务不生效,删掉的任务到点报错 - 模板在别的仓库 → 模板更新了,引用方毫无感知
补救办法:调 OpenAPI 的 BuildCrontabSync 手动同步。同步后新增任务的负责人是这次 API 的调用者。
七、什么时候会被自动清理
- 分支被删 → 该分支下所有定时任务清掉
- 仓库被删 → 全部清掉
- 仓库被归档 → 全部清掉
归档后恢复:在定时任务页面点同步按钮,或者随便往那个分支推一次。
八、夜间构建该跑什么
定时任务的价值不在"多跑几次",而在跑那些白天没空跑的东西:
main:
"crontab: 0 3 * * *":
- name: nightly
runner:
cpus: 8
stages:
- name: 全量测试
script: yarn test --coverage
- name: 依赖漏洞扫描
script: yarn audit || true
- name: 构建并推快照镜像
script: ./scripts/push-snapshot.sh
晚上机器空、白天有人。把重的活挪到夜里,是最省钱的优化——比调 cpus 有用。
下一篇聊另一种「和外部系统打通」:TAPD。