推荐用 github.com/robfig/cron/v3 实现准生产级定时任务,它支持秒级精度、时区隔离、并发控制;务必显式指定 time.Location,任务函数须无参无返回值,超时默认跳过,动态增删需 channel 串行管理,失败重试需手动封装。
用 github.com/robfig/cron/v3 实现准生产级定时任务
直接上手推荐用 cron/v3,它支持秒级精度、时区隔离、任务并发控制,且 API 清晰。别用老版本 v1 或 v2,它们不支持 Location 参数,本地时间错乱是常态。
常见错误:启动后任务没执行,或执行时间比预期晚 1 分钟——大概率是没传 *time.Location,默认用 UTC:
// ✅ 正确:显式指定上海时区
loc, _ := time.LoadLocation("Asia/Shanghai")
c := cron.New(cron.WithLocation(loc))
// ❌ 错误:用默认 UTC,导致北京时间任务延后 8 小时
c := cron.New()
- 任务函数必须无参数、无返回值,否则注册会 panic;需传参请闭包封装或用结构体方法绑定
- 若任务执行耗时超过调度间隔(比如每 10s 执行,但某次跑了 15s),
v3默认跳过下一次,避免堆积;如需并发运行,加cron.WithChain(cron.Recover(cron.DefaultLogger), cron.DelayIfStillRunning(cron.DefaultLogger)) - 注意
cron.New()不自动启动,记得调c.Start(),且程序退出前应c.Stop()防 goroutine 泄漏
Web 接口动态增删 Cron 任务要绕开全局单例
Web 管理后台常需要“新增一个每天凌晨 2 点发邮件的任务”,但 cron.Cron 实例不是线程安全的,不能在 HTTP handler 里直接 c.AddFunc(...) 后立刻生效——可能因并发写入 panic,或新加任务未被调度器感知。
正确做法是用 channel + 单 goroutine 统一管理:
type TaskOp struct {
Action string // "add", "remove"
Spec string
Func func()
Name string
}
var taskCh = make(chan TaskOp, 100)