iris本身不内置定时任务调度能力,必须借助gocron等第三方库在main函数中初始化并统一管理,禁止在http handler内用time.ticker启动goroutine,因其生命周期短、无法统一控制且易导致并发重复执行。

Iris 本身不内置定时任务调度能力,必须借助 Go 生态的第三方库或系统级机制来实现。直接在 iris.Context 或路由处理器里用 time.Ticker 启动 goroutine 是常见误操作——它会随 HTTP 请求生命周期意外终止,且无法统一管理、重启或监控。
为什么不能在 iris.Handler 里直接起定时器
HTTP handler 是短生命周期的:每次请求进来,app.Get("/", handler) 中的 handler 函数执行完就退出。如果在里面写 go func() { for range time.Tick(...) { ... } }():
- goroutine 可能被 GC 干扰或进程退出时静默丢失(尤其在开发阶段热重载时)
- 多个请求反复触发,导致同一任务并发执行多份
- 无法优雅停止:没有引用、无上下文绑定、无错误传播路径
-
iris.Context对象不可跨请求复用,里面封装的响应写入、超时控制等机制在定时逻辑中完全失效
推荐方案:用 gocron + iris 启动时初始化
选 gocron(非 ouqiang/gocron 的 Web 管理版,而是 github.com/go-co-op/gocron 这个轻量纯调度库)最稳妥。它支持 context 控制、任务取消、错误回调,且与 Iris 启动流程天然契合:
- 在
main()初始化 Iris 实例前,先创建gocron.Scheduler - 用
scheduler.StartAsync()启动调度器(非阻塞) - 所有定时任务注册在
app.Run()之前,确保只启动一次 - 利用
iris.RegisterOnInterrupt()或iris.RegisterOnServerShutdown()触发scheduler.Shutdown()
示例关键片段:
func main() {
scheduler := gocron.NewScheduler(time.Local)
// 注册任务(注意:不要传 *iris.Context)
scheduler.Every("5s").Do(func() {
fmt.Println("tick at", time.Now())
// 这里可调用你的业务函数,比如 db.Ping(), sendAlert()
})
app := iris.New()
app.Get("/health", func(ctx iris.Context) {
ctx.JSON(iris.Map{"ok": true})
})
// 启动前启动调度器
scheduler.StartAsync()
// 优雅关闭
app.RegisterOnServerShutdown(func() {
scheduler.Shutdown()
})
app.Run(iris.Addr(":8080"))
}
需要访问 Iris 依赖(如数据库、配置)怎么办
别把 *iris.Application 或 iris.Context 塞进定时任务闭包。正确做法是提前把依赖提取为全局变量或结构体字段:
- 数据库连接池(
*sql.DB)在main()初始化后赋值给包级变量,定时任务直接用 - 配置项(如
config.SMTPHost)用 struct 封装,在 scheduler 启动前注入到任务函数中 - 避免在定时函数里调用
app.ConfigureContainer()或尝试重建依赖图——Iris 的 DI 容器不保证 goroutine 安全
反例:scheduler.Every("1m").Do(func() { app.ConfigureContainer(...) }) —— 容器不是线程安全的,且该方法本就不该在运行时反复调用。
如果真要和 HTTP 请求联动(比如手动触发某次调度)
用 channel 或 sync.Map 实现“信号桥接”。例如定义一个 triggerChan chan string,在定时任务中 select 监听;HTTP handler 向它发信号:
- 定时逻辑保持独立,只做周期性检查或默认行为
- HTTP 接口不“执行任务”,只“通知调度器准备执行”
- 避免在 handler 里直接调
task.Run()—— 万一任务耗时长,会卡住 HTTP worker
这种模式下,定时器本质是轮询+事件驱动混合体,比强行把 cron 塞进 web 框架更可控。
最容易被忽略的一点:所有定时任务函数都应具备幂等性。网络抖动、进程重启、调度器延迟都可能导致同一任务被重复触发,不能假设“每 5 秒只执行一次”是绝对可靠的。











