Kratos 不内置定时任务调度,需借助 asynq(推荐,分布式、带重试)或 gocron(单机轻量);time.Ticker 因生命周期脱钩、无容错、不支持分布式等缺陷,不适用于生产。

kratos 本身不内置定时任务调度能力,它定位是微服务框架,不是作业调度平台。想在 Kratos 服务里跑定时逻辑(比如每5分钟拉一次配置、每天凌晨清理日志表、每小时统计订单量),得靠外部工具或手动集成——直接写 time.Ticker 最快,但不推荐用于生产;用 asynq 或 gocron 是更稳妥的选择。
为什么不能直接用 time.Ticker 启动 goroutine?
能跑通,但隐患多:
• 它和 HTTP/gRPC server 生命周期脱钩,kratos run 停止时,time.Ticker 可能还在跑,导致资源泄漏
• 没有错误重试、失败告警、并发控制,一个 panic 就让整个定时逻辑静默退出
• 多实例部署时会重复执行(比如 3 台机器都每小时发一次邮件)
• 无法动态启停、修改周期,改代码就得发版
用 asynq 接入定时任务(推荐)
asynq 是 Go 生态中成熟度高、自带 Web UI 和重试机制的分布式任务队列,天然适合与 Kratos 配合:它用 Redis 做后端,天然支持多实例互斥;Kratos 的 server 层可统一管理其生命周期。
- 安装依赖:
go get github.com/hibiken/asynq - 在
internal/server下新建asynq.go,注册到NewServer中,确保asynq.Server随服务启动/关闭 - 定义定时任务:
asynq.NewTask("daily_report", nil, asynq.TaskID("report_20261102")),再用client.Schedule设置 cron 表达式(如"0 0 * * *"表示每天零点) - 避免在
service层直接调用asynq——应封装成biz接口,例如biz.Reporter.ScheduleDailyReport(),保持分层清晰
用 gocron 做单机轻量定时(仅限开发/小流量)
如果压根没上 Redis,或者只是本地调试一个每秒打日志的 demo,gocron 更轻:
• 它基于 time.Ticker 封装,但提供了 .Start()/.Stop() 方法,能绑定到 Kratos 的 server 生命周期
• 支持链式调用:gocron.Every(1).Hour().Do(func(){...})
• 注意:必须在 cmd/server/main.go 的 app.Run() 前启动,否则服务退出时 goroutine 未被回收
• 不要把它用在需要强一致性的场景(比如“只允许一台机器执行”的定时补偿),它没有分布式锁
关键收口点:别忘了注册进 Wire 依赖图
Kratos 用 wire 管理依赖,定时任务组件(无论是 asynq.Server 还是 gocron.Scheduler)必须作为 ProviderSet 注入,否则:
• wire_gen.go 不会生成初始化代码
• app.Run() 无法触发它的 Start() 方法
• 日志里看不到 “scheduled task started” 这类提示,你甚至不知道它有没有生效
典型错误是把定时逻辑写在 init() 函数里——Wire 不感知,Kratos 不接管,等于裸奔


















