如果连接在 10 秒前关闭,如何取消进一步处理?
有c.Request.Context().Done()
但找不到有关如何使用它的示例。
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
time.Sleep(10 * time.Second) // or some db operation
log.Print("Processing")
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run()
}
最佳答案
您可以异步运行长时间运行的操作,并将其发送到 channel 以表示完成。
然后你阻塞在那个完成 channel 和 c.Request.Context().Done()
与 select
陈述:
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
signal := make(chan struct{}, 1)
go longRunningOperation(signal)
select {
case <-signal:
close(signal) // remember to clean up after yourself
// move on, will print "Processing"
case <-c.Request.Context().Done():
// abort
return
}
log.Print("Processing")
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run()
}
func longRunningOperation(signal chan<- struct{}) {
time.Sleep(10 * time.Second)
signal <- struct{}{} // signal that this operation has finished
}
这种方法的缺点是,长时间运行的操作本身会继续执行。当
main
时 Goroutines 退出程序的函数返回,实际情况并非如此gin
服务器。所以这可能不是你想要的。在数据库操作的情况下,大多数 API 需要一个
context.Context
参数,可用于检测请求取消。所以你可以通过 c.Request.Context()
沿着调用链向下以确保异步长时间运行的操作在客户端断开连接时也终止。func Handler(c *gin.Context) {
signal := make(chan struct{}, 1)
go longRunningOperation(c.Request.Context(), signal)
...
}
func longRunningOperation(ctx context.Context, signal chan<- struct{}) {
if err := doSomethingContext(ctx); err != nil {
return
}
signal <- struct{}{} // signal that this operation has finished (successfully)
}
关于开始请求取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62740163/