Cron 定时任务:表达式语法与排错

从 crontab 五字段到云调度时区陷阱:用 Towalles 生成与解析 Cron,避免任务不跑或重复触发。

· 全部指南

Cron 表达式是什么

Cron 是一种按时间触发任务的调度语法,广泛用于 Linux crontab、Kubernetes CronJob、GitHub Actions、AWS EventBridge 以及各类 SaaS 平台。表达式用五个(有时六个)字段描述「何时执行」:分、时、日、月、周(部分系统还有秒)。看起来很短——0 9 * * 1-5 表示「工作日早上 9 点」——但字段顺序或符号写错,任务可能永远不调度,或在错误时间重复执行。

Towalles 的 crontab-generator 可在浏览器本地可视化生成表达式,不必死记字段顺序。cron-parser 则反向解析:粘贴表达式即可查看未来几次触发时间。两者都在本地运行,适合在提交到生产 crontab 或 K8s CronJob 清单之前先验证。

典型场景:团队需要在工作日凌晨 2:30 做数据库备份。打开 crontab-generator,设置分 30、时 2、日 *、月 *、周 1-5,复制表达式到部署仓库。合并前把同一字符串贴进 cron-parser,核对列出的时间是否符合值班预期——若服务器用本地时区,还要考虑夏令时切换。

常见字段与符号

标准五字段顺序为:分 时 日 月 周。星号 * 表示「任意值」;逗号 , 枚举(如分字段 0,15,30,45);连字符 - 表范围(9-17);斜杠 / 表步进(*/15 每 15 分钟)。

不同平台有差异:Linux crontab 与 Kubernetes 的「周」字段可能把周日记为 07;GitHub Actions 默认 UTC,0 9 * * * 是 UTC 9 点而非北京时间 9 点;云厂商有的用六字段且秒在最前。不要照搬某一家的速查表到另一家。

常见错误:把「日」和「周」位置写反;两个日字段都写 * 时多数表示每天,但在 31 号会有特殊行为;写 0 0 31 2 * 期待 2 月 31 日——永远不会触发。另有误区:小时字段 */24 并不等价于「每天一次」,与 0 0 * * * 在时区边界上可能不同。

排错建议

任务「没跑」时先查时区:服务器 crontab 常用机器本地时区,云函数常为 UTC。把表达式贴进 cron-parser,对比「下次执行时间」与目标主机 date 输出。若刚好差一个 UTC 偏移,问题多半在时区配置。

重叠执行是另一类静默故障:任务单次要 40 分钟却每 30 分钟调度一次,会堆积进程、打满连接池甚至造成半写入。可用 timereta-calculator 估算耗时,再拉大间隔或在脚本里加互斥锁。

每月 31 日的任务在 2 月会跳过——这是预期行为。若要「每月最后一天」,需用平台扩展语法,或在 28–31 日运行并由脚本判断次日是否换月。

Staging 验证流程:复制生产表达式 → 在 staging 时钟下用 cron-parser 核对 → 用相同环境变量手动跑一次脚本 → 上线 → 在日志里盯前三次执行。运维文档里应写清人类可读含义,不要只留原始字符串。

安全与运维

Cron 表达式本身不是秘密,会明文出现在清单、Git 与监控里。脚本路径、API 密钥、数据库口令应通过环境变量、Vault 或 sealed secrets 管理,避免写在命令行里被 ps 泄露。

遵循最小权限:为定时任务单独建服务账号,只授予必要权限;与交互账号同样周期轮换凭证;记录开始/结束与退出码,对连续失败告警而非单次抖动。

生产变更纪律:在 staging 用相同时区与表达式试跑;脚本尽量幂等,避免重复执行导致重复扣费;在版本库保留回滚用 crontab 片段。Towalles 工具帮你设计调度;能否安全上线仍取决于部署流程与可观测性建设。

相关工具