Go 中如何运行定时(cron)任务?

在 Go 程序里跑 cron 定时任务:用 robfig/cron 库注册表达式调度,含安装、AddFunc 示例、带秒的六字段格式、time.Ticker 替代方案与 FAQ。

最佳实践
Go 中如何运行定时(cron)任务?封面

Go 标准库没有 cron 表达式调度器,社区事实标准是 robfig/cron:import 后 cron.New() 创建调度器,AddFunc("表达式", 函数) 注册任务,Start() 启动。 只要进程活着,任务就按点执行。

1. 安装

go get github.com/robfig/cron/v3

2. 最小示例:每分钟打印一次

package main

import (
    "fmt"

    "github.com/robfig/cron/v3"
)

func main() {
    c := cron.New()

    // 注册任务:标准五字段表达式
    c.AddFunc("* * * * *", func() {
        fmt.Println("Hello world!")
    })

    c.Start()

    // 阻塞主 goroutine,实际项目中用 select{} 或等退出信号
    select {}
}

表达式与系统 crontab 一致:分 时 日 月 星期。如每天凌晨 3 点半:"30 3 * * *"

3. 需要秒级精度

v3 默认五字段;要六字段(带秒)就显式开解析器:

c := cron.New(cron.WithSeconds())
c.AddFunc("*/10 * * * * *", func() { fmt.Println("每 10 秒") })

4. 常用进阶项

  • 描述性调度c.AddFunc("@every 5m", fn)@daily@hourly 等宏。
  • 带参数任务c.AddJob("0 * * * *", myJob{client: db}),实现 Run() 方法的类型。
  • 防重叠cron.New(cron.WithChain(cron.SkipIfStillRunning(logger))),上一轮没跑完就跳过。
  • 指定时区:表达式前加 CRON_TZ=Asia/Shanghai,或 cron.WithLocation(loc)

5. 简单场景可以不上库

固定间隔的轮询用标准库 time.Ticker 就够了:

ticker := time.NewTicker(5 * time.Minute)
for range ticker.C {
    doWork()
}

但它表达不了"每天凌晨 2 点"这种日历语义——那才是 cron 库的价值。

观测云对照

进程内调度器绕过了系统 cron,意味着 /var/log/cron 里查不到它——任务跑没跑全靠应用自己说。Go 服务接入观测云 APM 后,定时任务的关键路径可以埋点成 span;任务日志统一采集后配心跳式监控器:计划时间窗口内没有成功日志就告警,进程挂了、调度器 panic、任务卡死三种情况都能覆盖。

常见问题(FAQ)

Q:程序重启后错过的时间点会补跑吗?
A:不会。robfig/cron 是纯内存调度器,进程停了就丢了。关键任务需要持久化调度的话,考虑 Quartz 类的外部调度中心,或用系统 cron + 幂等脚本。

Q:AddFunc 的函数 panic 会怎样?
A:v3 默认 recover 并记日志(取决于 logger 配置),调度器本身不会挂。但建议函数内部自己兜住错误,避免任务状态不一致。

Q:能动态增删任务吗?
A:可以。AddFunc 返回 EntryID,之后 c.Remove(id) 删除;运行中随时可加新任务,c.Entries() 查看现有调度。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台