不能直接 for range ticker.c,因任务超时会导致并发执行压垮下游、信号积压丢失且无报错、无 context 控制引发 goroutine 泄漏;正确做法是用独立 goroutine + select + ctx.done() 消费。

直接上结论:简单轮询用 time.Ticker,带 cron 表达式、时区、失败重试等需求,必须用 cron/v3 或 gocron;别自己封装 time.AfterFunc 递归调用,也别在主线程里直接 for range ticker.C。
为什么不能直接 for range ticker.C?
这是最常踩的坑。看起来简洁,实际一出问题就连锁崩溃:
— 如果 doSomething() 耗时超过 ticker 间隔(比如 5 秒任务跑了 8 秒),下一次 tick 信号会立刻触发,导致并发执行,可能压垮下游;
— ticker.C 是带缓冲的 channel,但缓冲区只有 1,积压信号会被丢弃,调度“跳过”却不报错;
— 没 context 控制,服务退出时 ticker 不 stop,goroutine 泄漏,内存缓慢上涨。
正确做法是启动独立 goroutine 消费 channel,并用 select 配合 ctx.Done() 退出:
ticker := time.NewTicker(5 * time.Second)<br>defer ticker.Stop()<br>go func() {<br> for {<br> select {<br> case go func() {<br> defer func() { if r := recover(); r != nil { log.Printf("panic: %v", r) } }()<br> doSomething()<br> }()<br> case return<br> }<br> }<br>}()
cron/v3 怎么启用秒级精度?
cron/v3 默认只认五段式表达式(分、时、日、月、周),写 "*/5 * * * * *" 会被静默截断成 "* * * * *",变成每分钟执行一次。
必须显式传 cron.WithSeconds() 选项:
c := cron.New(cron.WithSeconds(), cron.WithLocation(time.FixedZone("CST", 8*60*60)))<br>c.AddFunc("*/5 * * * * *", func() { /* 每 5 秒 */ })
注意两点:
—
WithSeconds() 必须在 New() 时传入,之后无法动态开启;— 时区要单独配,
WithLocation() 和 WithSeconds() 是并列选项,缺一不可;— 所有任务共用同一个
cron.Cron 实例,别为每个任务 new 一个,否则调度 goroutine 冲突、CPU 毛刺。
定时任务里调 HTTP 或 DB 为什么总 panic 或超时?
不是定时逻辑的问题,是资源没管好:
— HTTP client 别每次新建:http.DefaultClient 可复用但不设 timeout,推荐自定义 &http.Client{Timeout: 10 * time.Second};
— DB 连接池(如 *sql.DB)必须全局复用,且在服务启动时初始化;绝对不要在 AddFunc 回调里 sql.Open(),会快速耗尽文件描述符;
— 多个任务共写同一变量(比如计数器),必须加 sync.Mutex 或用 atomic.Int64,否则数据竞争;
— panic 不会自动恢复:gocron 提供 .WithRecover(),cron/v3 得手动包一层 recover(),否则一次 panic 整个调度器停摆。
如何让定时任务支持热重载配置?
硬编码 "0 0 * * *" 在代码里等于放弃运维能力。
真实可行的做法只有两种:
— 把表达式存在外部存储(Redis / etcd / 文件),服务启动后定期轮询读取,变化时调用 c.Remove() + c.AddFunc() 替换(注意:这两个方法不是 goroutine-safe,得加锁);
— 用 fsnotify 监听配置文件变更,触发 reload;
关键点:
— cron.Cron 实例本身不能重建,只能增删 job;
— 删除 job 前确保它已执行完(c.Entries() 可查状态);
— 新增 job 后记得调用 c.Start()(如果之前 Stop 过)——但通常保持运行态更安全。
别指望“改完配置自动生效”,中间总有几秒窗口期,业务得有幂等性兜底。
真正难的从来不是怎么写定时器,而是怎么让它在高并发、网络抖动、进程重启、配置变更这些现实条件下,既不丢任务,也不重复跑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











