Cron 表达式:写对,且知道它什么时候会坑你

从自然语言需求反推表达式,并检查时区、夏令时、月末、重入四类坑。

什么时候用:定时任务的时间总是不对,或者月末跑一次结果跑了两次,排查半天。

提示词(整段复制)

你是运维工程师。请把下面的自然语言需求翻成 cron 表达式,并做风险检查。

需求描述:{{需求}}
运行环境:{{环境与时区}}
任务耗时:{{任务耗时}}
是否允许多实例部署:{{多实例}}

输出要求:
1. **表达式**:给出 cron(5 段)与 Quartz(6 段)两种写法,标注差异。
2. **逐段解释**:每个字段的值意味着什么,用一句话说明(不要只给表格)。
3. **四类坑逐个检查**:
   ① 时区:容器/服务器/数据库时区是否一致,不一致时怎么处理;
   ② 夏令时:所在时区是否有 DST,跳变那一小时任务会怎样;
   ③ 月末/闰年:`每月的 31 日` 在 2 月会怎样,`每 30 分钟` 与 `每小时的第 30 分` 的区别;
   ④ 重入:任务耗时超过间隔时会怎样,多实例部署会不会重复执行。
4. **验证方法**:给出命令,列出未来 5 次触发时间,确认与预期一致。
5. **兜底建议**:加锁、超时、失败重试分别怎么做。

约束:
- 如果需求本身有歧义(如「每月初」),先列出 2 种理解让你选,不要擅自决定。

复制时把 {{变量}} 换成你自己的内容;变量名不要改,改了模型容易把它当普通文字。

要替换的变量

变量示例值
{{需求}}每个月最后一个工作日的下午 5 点半跑一次结算
{{环境与时区}}Docker 容器,宿主机 UTC,业务在 Asia/Shanghai
{{任务耗时}}通常 3 分钟,极端情况 40 分钟
{{多实例}}是,两台机器

实操建议

常见问题

cron 能表达「每月最后一个工作日」吗?

不能。只能每天跑一次,在脚本里判断「今天是不是本月最后一个工作日」,不是就直接退出。

多实例怎么避免重复执行?

分布式锁(Redis SETNX 带过期时间)或数据库唯一约束,二者选一,别靠「只在一台机器上配 cron」。

配套工具