用标准库+轻量第三方库构建可靠调度器:简单任务用time.Ticker/AfterFunc,复杂需求选gocron;需持久化、去重、可观测性及优雅关闭。

核心思路:用标准库+轻量第三方库构建可靠调度器
Go 本身没有内置的“定时任务调度器”,但通过 time.Ticker、time.AfterFunc 和成熟库(如 robfig/cron/v3 或 go-co-op/gocron)就能快速搭建生产可用的调度系统。关键不是从零造轮子,而是选对抽象层级:简单场景用标准库,复杂需求(Cron 表达式、分布式、持久化)用专用库。
基础定时任务:用 time.Ticker 和 time.AfterFunc 足够
适合执行频率固定、不依赖 Cron 语法、无故障恢复要求的任务(如每 5 秒检查一次内存、每分钟上报指标)。
- 单次延时执行:用
time.AfterFunc(delay, f),返回func()可取消 - 周期性执行:用
time.NewTicker(interval)配合select监听t.C,注意在退出前调用t.Stop() - 避免 goroutine 泄漏:所有定时器都应有明确生命周期管理,建议封装成结构体并提供
Stop()方法
进阶调度:用 gocron 实现 Cron 表达式与任务管理
go-co-op/gocron 是当前最活跃、API 清晰的 Go 调度库,支持 Cron 表达式、链式配置、任务分组、手动触发和错误回调。
- 安装:
go get github.com/go-co-op/gocron - 基本用法:
s := gocron.NewScheduler(time.UTC)→s.Cron("0 * * * *").Do(task) - 任务可绑定参数、设置标签、指定运行次数(
LimitRunsTo(10))、失败重试(WithDelayBetweenRuns(5 * time.Second)) - 运行时控制:
s.Start()/s.Stop()/s.Remove(task)/s.RunByTag("notify")
生产级增强:加入持久化、去重与可观测性
单机调度满足不了高可用要求。上线前建议补上三块能力:
立即学习“go语言免费学习笔记(深入)”;
- 任务状态持久化:将任务定义和上次执行时间存入 sqlite/postgresql,重启后自动恢复;可用
gocron.WithDistributedLocker+ redis 实现分布式锁防重复 - 执行去重与幂等:在任务入口加唯一 ID(如基于任务名+时间窗口哈希),结合 redis Set 记录已执行 ID,避免网络重试导致重复处理
- 可观测性:用
prometheus.Clientgolang暴露任务延迟、失败数、运行中数量等指标;关键任务加日志上下文(taskID、startAt、duration)
基本上就这些。不复杂但容易忽略的是:调度器本身要作为服务长期运行,务必用 signal.Notify 捕获 os.Interrupt 和 syscall.SIGTERM,优雅关闭所有 ticker 和正在执行的任务。