在这种情况下,Go HTTP 处理程序 goroutine 是否应该立即退出?



我有一个像这样的Go HTTP处理程序:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
time.Sleep(5 * time.Second)
fmt.Println("I am still running...........")
fmt.Fprint(w, "cancellation testing......")
})

API 工作正常,然后在请求完成之前使用 curl,我故意用Control-C终止 curl 命令,在服务器端我确实看到client cancelled....................!!!!!!!!!被注销,但过了一会儿I am still running...........也被注销了,我认为这个 goroutine 会立即终止!

那么,这是想要的行为,还是我做错了什么?

如果这是意料之中的,既然无论什么goroutine都会完成它的工作,那么提前取消的意义何在?

如果我做错了什么,请帮助指出我正确的方法。

您创建了一个可以取消的contex.Context,当客户端关闭连接时会取消该,但您不检查上下文,并且如果取消,处理程序不会执行任何不同操作。上下文仅执行超时和取消信号,它没有杀死/终止goroutines的权力或意图。goroutines本身必须监控此类取消信号并对其采取行动。

因此,您看到的是代码的预期输出。

你想要的是监视上下文,如果它被取消,则从处理程序"立即"返回。

当然,如果你正在"睡觉",你无法同时监控上下文。所以改用time.After(),如本例所示:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
fmt.Println("client cancelled....................!!!!!!!!!")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
select {
case <-time.After(5 * time.Second):
fmt.Println("5 seconds elapsed, client didn't close")
case <-ctx.Done():
fmt.Println("Context closed, client closed connection?")
return
}
fmt.Fprint(w, "cancellation testing......")
})

相关内容

最新更新