time.Ticker适合轻量周期任务但不可直接用于生产,需防阻塞、recover panic、避免耗时操作;cron/v3支持秒级需显式启用,应复用单例、注意时区与表达式匹配,并强化幂等性、监控和外部调度保障。
用 time.Ticker 实现简单周期任务,但别直接上生产
如果只是每 5 秒打印一次日志、或轮询某个本地状态,time.Ticker 足够轻量且可控。它底层基于系统单调时钟,不会因系统时间跳变而错乱。
但要注意:time.Ticker 不处理 panic、不支持任务并发控制、不记录执行历史、挂了就真挂了——一旦 tick 通道被阻塞(比如任务耗时超过间隔),后续所有 tick 都会堆积在 channel 缓冲区,最终导致内存上涨甚至 OOM。
- 务必用
select+default非阻塞读取,或设合理缓冲大小(如time.NewTicker(5 * time.Second)后只取最新一个 tick) - 任务函数必须 recover panic,否则整个 ticker goroutine 会退出
- 不要在 ticker 回调里做 HTTP 请求、数据库写入等不可控延迟操作
cron 包能解析 crontab 表达式,但默认不支持秒级精度
主流选择是 github.com/robfig/cron/v3,它兼容 Unix cron 格式(0 0 * * * ? 这类带秒的表达式需显式启用秒字段)。
默认初始化 cron.New() 使用的是标准五段式(分、时、日、月、周),没有秒;要支持秒,必须用 cron.New(cron.WithSeconds())。否则你写 "*/5 * * * * *" 会被静默截断为 "* * * * *",实际变成每分钟执行一次。
- 使用前检查
cron.New(...)的选项是否匹配你的表达式格式 - 注意时区:默认用
time.Local,若部署在 UTC 服务器但业务按北京时间调度,得传入cron.WithLocation(time.FixedZone("CST", 8*60*60)) - 任务函数返回 error 不会重试,也不会自动告警,需自行包装日志和监控
多个定时任务共存时,用单例 cron.Cron 实例统一管理
每个 cron.Cron 实例启动一个独立 goroutine 调度器。如果为每个任务 new 一个 cron.Cron,不仅浪费 goroutine,还会因各自 tick 时间不同步导致 CPU 毛刺。