robfig/cron/v3默认只支持五段表达式,六段如"/5 "需显式传cron.withseconds(),否则静默忽略、任务不注册;必须调c.start()、设时区、recover panic,否则任务永不执行。

robfig/cron/v3 默认不支持秒字段,写成六段表达式会静默失败——不是报错,而是根本没注册上任务。
为什么 "*/5 * * * * *" 加了却从不执行
这是最常踩的坑:v3 默认只认五段表达式(分、时、日、月、周),"*/5 * * * * *" 是六段,但你没传 cron.WithSeconds(),解析器直接忽略,AddFunc() 返回 error 却不 panic,也不打日志(默认 logger 不输出 warning)。结果就是 c.Entries() 返回空 slice,你以为加成功了,其实什么都没发生。
- 验证方式:
fmt.Printf("entries: %+v", c.Entries()),为空说明表达式没被接受 - 正确做法:初始化时必须加
cron.WithSeconds(),且表达式严格六段,首字段是秒 - 错误写法:
cron.New() + "*/5 * * * * *"→ 静默丢弃;cron.New(cron.WithSeconds()) + "0 */2 * * *"→ 段数不匹配,同样失败 - 别混用 Quartz 语法:
"0 0 * * * ?"中的?v3 不识别,会解析失败
cron.ParseStandard() 和 cron.NewParser() 的区别在哪
cron.ParseStandard() 只支持五段标准 Unix 格式,返回 *cron.Entry 或 error;而 cron.NewParser() 是底层构造器,你要手动指定字段掩码,比如秒级需 cron.NewParser(cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)。日常开发几乎不用后者——直接用 cron.New(cron.WithSeconds()) 更安全。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 动态加载配置时,务必先用
cron.ParseStandard(spec)或cron.ParseQuartz(spec)主动校验,别等AddFunc()才发现格式错 - 空格敏感:
"0 0 * * *"(双空格)会被拒绝,必须单空格分隔 - 字段值大小写不敏感,
"MON,WED"和"mon,wed"都行,但"SUN"表示周日,"7"在 v3 中不被接受(只认 0–6)
本地时间“每天零点”为什么总在早上 8 点跑
v3 默认所有时间计算走 time.UTC,哪怕你机器 TZ=Asia/Shanghai 也无效。"0 0 * * *" 实际是在 UTC 0 点(北京时间 8:00)触发。这不是 bug,是设计如此——必须显式传时区。
- 正确初始化:
cron.New(cron.WithLocation(time.Local)),别用time.LoadLocation("Asia/Shanghai"),容器里常因缺tzdata失败 - Docker 镜像要装 tzdata 并设
ENV TZ=Asia/Shanghai,否则time.Local会 fallback 到 UTC - 验证是否生效:
next := c.Entry(ID).Schedule.Next(time.Now()); fmt.Println(next),看小时数是不是你本地预期的值
高频任务(如每秒)为什么延迟越来越大
v3 底层靠每秒 ticker 触发,然后遍历全部 job 调用 Next() 算下次执行时间。100 个 job 时,每次 tick 都要算 100 次,如果某个 job 的函数执行超时,还会阻塞整个调度循环(v3 默认串行执行)。
- 每秒任务慎用:
"* * * * * *"看似简单,实际压力不小;优先考虑time.Ticker+ 协程池 - 长耗时 job 必须异步化:在
AddFunc里起 goroutine 做实际工作,避免阻塞调度器 - 别在 job 里反复 new DB 连接或 HTTP client:连接泄漏 + panic 风险叠加,一次 panic 就让整个调度器停摆(默认不 recover)
真正麻烦的从来不是写对那条表达式,而是忘了 c.Start()、主 goroutine 闪退、时区没设、panic 没 recover——这些点漏一个,任务就永远安静地躺在那儿,不报错,也不执行。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










