duanjiong1952 2018-05-23 09:39
浏览 114
已采纳

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

I have one Go HTTP handler like this:

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......")
})

The API works fine, then with curl before the request finish I terminate the curl command deliberately with Control-C, and on server side I do see the client cancelled....................!!!!!!!!! get logged out, but after a while the I am still running........... get logged out also, I thought this goroutine will be terminated immediately!

So, is this desired behaviour, or I did something wrong?

If it is expected, since whatever the goroutine will complete its work, then what is the point of the early cancellation?

If I did something wrong, please help to point me out the correct way.

  • 写回答

1条回答 默认 最新

  • douxianji6104 2018-05-23 09:47
    关注

    You create a contex.Context that can be cancelled, which you do cancel when the client closes the connection, BUT you do not check the context and your handler does nothing differently if it is cancelled. The context only carries timeout and cancellation signals, it does not have the power nor the intent to kill / terminate goroutines. The goroutines themselves have to monitor such cancellation signals and act upon it.

    So what you see is the expected output of your code.

    What you want is to monitor the context, and if it is cancelled, return "immediately" from the handler.

    Of course if you're "sleeping", you can't monitor the context meanwhile. So instead use time.After(), like in this example:

    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......")
    })
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog