新项目用 github.com/robfig/cron/v3 或 gocron;老项目升级需加 cron.withseconds() 和 cron.withlocation(),否则任务不触发、时区错乱、panic 崩溃;cron.new() 后必须调 c.start() 且主 goroutine 不能立即退出。

别用 robfig/cron(v1/v2),新项目直接上 github.com/robfig/cron/v3 或 gocron;老项目升级必须加 cron.WithSeconds() 和 cron.WithLocation(),否则任务不触发、时区错乱、panic 崩溃三连击。
为什么 cron.New() 加了任务也不执行
默认调度器是“暂停态”,cron.New() 只建了个空壳,不启动后台 goroutine。没调 .Start(),所有 AddFunc() 都白加。
- 必须显式调用
c.Start()才真正开始 tick - 主 goroutine 不能立刻退出:加
select {}或time.Sleep(),否则进程闪退,任务根本没机会跑 -
defer c.Stop()是好习惯,但它不等于Start(),顺序也不能反——先Start(),再defer Stop() - v3 中如果忘了
cron.WithSeconds()却写了六段表达式(如"*/5 * * * * *"),解析失败且静默忽略,日志里可能只有一行 warning,任务永远不触发
秒级任务怎么写才不踩坑
v3 默认只认五段 cron 表达式(分时日月周),要支持秒必须初始化时传 cron.WithSeconds(),且表达式严格六段(秒分时日月周),末尾不能带 ?(那是 Quartz 语法,v3 不原生支持)。
- 正确写法:
cron.New(cron.WithSeconds())+"*/5 * * * * *" - 错误写法:
cron.New()+"*/5 * * * * *"→ 解析失败,AddFunc()返回 error 但不 panic,容易漏掉 - 别混用:
@every 5s是 v2 的 descriptor,v3 已移除,用了会报unrecognized descriptor - 高频任务(如每秒)慎用:v3 底层每秒遍历全部 job 算 next 时间,100+ job 时延迟明显,优先考虑
time.Ticker
时区错成 UTC 怎么修复
默认用 time.UTC 解析 cron 表达式,哪怕你本地 TZ=Asia/Shanghai,"0 0 * * *" 也是在 UTC 0 点(北京时间早 8 点)跑,不是你想要的“每天凌晨”。
- 初始化必须显式传时区:
cron.New(cron.WithLocation(time.Local))——time.Local比time.LoadLocation("Asia/Shanghai")更可靠,后者在容器里常返回 error - 验证是否生效:打印
c.Entry().Schedule.Next(time.Now()),看返回时间的小时数是否符合预期 - 注意:时区只影响表达式解析,不影响
time.Now()在任务里的行为;任务内打日志仍需自己格式化时区 - Docker 镜像里没装 tzdata?
time.LoadLocation会失败,time.Local是 fallback 最优解
AddFunc() 里 panic 会导致整个调度器挂掉
v3 默认不 recover 任何 panic,一个任务空指针或除零,整个 c.Start() 循环退出,后续所有任务停摆,且无明确日志提示。
- 最简单方案:每个
AddFunc()包一层defer func() { recover() }(),至少打条 log - 更规范做法:用
cron.WithChain(cron.Recover(cron.DefaultLogger)),但注意它只捕获 panic,不处理业务 error - 闭包捕获循环变量是高发雷区:
for i := range jobs { c.AddFunc("...", func() { use(i) }) }→ 所有任务都用最后一个i值,必须显式传参:func(i int) { ... }(i) - 长生命周期对象(DB conn、HTTP client)别在
AddFunc()里反复 new,外部初始化后闭包捕获或显式传入,避免连接泄漏
真正麻烦的从来不是“怎么加个定时任务”,而是“任务挂了没人知道”“时间总差 8 小时”“上线后某天突然全量漏触发”——这些坑都在初始化那几行配置里埋着,多看一眼 cron.WithLocation() 和 cron.WithSeconds(),比后期查三天日志划算得多。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











