Revel 框架不提供原生异步控制器,但可通过 AsyncTask 封装 goroutine 实现安全异步;直接 go func() 会导致资源泄漏、panic 静默失败、结果不可知;必须避免在后台 goroutine 中访问请求上下文 c,推荐用值传递或独立队列通信。

Revel 框架本身不提供原生异步控制器,但你完全可以在不阻塞 HTTP 请求的前提下,安全地把耗时逻辑(比如第三方 API 调用、文件生成、复杂查询)挪到后台 goroutine 执行。关键不是“能不能开 goroutine”,而是“怎么确保它不泄漏、不丢失、不干扰请求生命周期”。
为什么不能直接 go func() { ... }()?
看似简单的一行 go 会埋下三个隐患:
- goroutine 可能比请求生命周期更长,导致内存/连接/资源无法释放;
- 如果任务 panic,没有 recover 机制,会静默失败;
- 无法感知任务是否完成、是否出错,后续日志、监控、重试都无从谈起。
Revel 的拦截器链(intercept.go)是串行执行的,主线程一旦返回 revel.Result,请求上下文就进入销毁流程 —— 此时后台 goroutine 若还在读写 c.Params 或 c.RenderArgs,就是典型的竞态访问。
用 AsyncTask 封装 goroutine + channel 等待结果
推荐在控制器中显式构造一个带超时和错误传递的异步任务封装:
App.OnAppStart
- 在
app/init.go的init()函数里,用revel.App.OnAppStart启动常驻 goroutine; - 用
chan或sync.Map做内存队列(小流量)或对接 Redis 队列(生产); - 避免在 goroutine 内引用任何
*revel.Controller实例或其字段 —— 它们只在请求周期内有效。
示例启动代码:
var taskQueue = make(chan map[string]interface{}, 100)
<p>func init() {
revel.InterceptMethod((<em>App).Before, revel.BEFORE)
revel.App.OnAppStart(func() {
go func() {
for task := range taskQueue {
// 处理 task,不依赖任何 c.</em>
sendNotification(task)
}
}()
})
}
</p>
控制器中只需投递:
revel.Result











