beego 本身不提供原生定时任务模块,需集成 robfig/cron/v3 等第三方库;推荐在 main() 中初始化 cron(启用秒级)、添加任务、调用 start() 后用 select{} 阻塞主线程,并确保数据库与配置已在之前完成加载。

Beego 中没有内置定时任务模块,得自己集成
Beego 本身不提供类似 cron 或 schedule 的原生定时任务能力。官方文档里也明确说明它专注 Web 框架职责,定时逻辑需由开发者自行引入第三方库或系统级调度(如 Linux cron)来补充。
最常用、与 Beego 兼容性好且轻量的方案是引入 robfig/cron/v3 —— 它支持秒级精度、表达式解析、任务并发控制,且 Go module 友好。
容易踩的坑:robfig/cron/v3 的 Start() 是非阻塞的,如果主程序在启动定时器后立刻退出(比如没加 select{} 或 time.Sleep),任务根本不会执行。
如何在 Beego 应用启动时注册并运行 cron 任务
推荐把定时任务初始化放在 main.go 的 main() 函数末尾,在 beego.Run() 之前完成注册和启动。这样能确保 Beego 的配置(如日志、数据库连接)已就绪,任务可安全调用业务逻辑。
实操建议:
- 用
cron.New(cron.WithSeconds())启用秒级支持(默认只到分钟) - 通过
c.AddFunc("0/30 * * * * ?", func(){...})添加每 30 秒执行一次的任务(注意:带秒的表达式必须 6 位) - 调用
c.Start()后,**必须阻塞主线程**,例如:select{}或signal.Notify(..., os.Interrupt) - 避免在定时函数中直接使用
beego.BeeApp.Handlers等未初始化的全局状态
示例片段:
c := cron.New(cron.WithSeconds())
c.AddFunc("0/10 * * * * ?", func() {
beego.Info("执行每 10 秒一次的清理任务")
// 这里可调用你封装好的 service.CleanExpiredData()
})
c.Start()
beego.Info("Cron 已启动")
select {} // 阻塞,保持进程存活
如何让定时任务访问 Beego 的配置和数据库
Beego 的 beego.AppConfig 和数据库实例(如 orm.RegisterDataBase 注册的)在 init() 或 main() 开头就已加载,只要不在 goroutine 启动前访问未初始化部分,就可以直接用。
常见错误现象:任务中调用 orm.QueryTable(...) 报 no registered database —— 原因是数据库注册代码写在了 beego.Run() 之后,或被条件编译跳过。
实操建议:
- 数据库注册务必放在
main()函数开头、c.Start()之前 - 读取配置统一用
beego.AppConfig.String("mysql::host"),不要依赖conf/app.conf文件路径硬编码 - 若任务逻辑复杂,建议封装成独立 service 包,接收
*orm.Ormer或配置结构体作为参数,提升可测性
生产环境要注意信号处理和优雅关闭
Linux 下用 systemd 或 supervisord 管理 Beego 进程时,收到 SIGTERM 后应停止 cron 并等待正在运行的任务结束,否则可能中断数据库事务或写一半的日志。
robfig/cron/v3 提供了 c.Stop(),但它**不会等待已触发但未执行完的任务**。需要手动配合上下文控制:
- 给每个任务函数传入
context.Context,并在关键操作中检查ctx.Err() - 注册
os.Interrupt和syscall.SIGTERM,先调c.Stop(),再用time.AfterFunc(5 * time.Second, os.Exit)设超时兜底 - 避免在定时任务里起长期 goroutine(如
for { select {...} }),这会让Stop()失效
真正难处理的是那些「启动即长跑」型任务(比如监听 Redis Stream),它们不属于 cron 调度范畴,得单独设计生命周期管理 —— 这点常被忽略。











