dropbox1111 2017-04-10 11:23
浏览 133
已采纳

使用golang在每个请求上执行上下文超时

I am trying to handle context timeout for every request. We have following server structures:

enter image description here

Flow overview:

Go Server: Basically, acts as a [Reverse-proxy].2

Auth Server: Check for requests Authentication.

Application Server: Core request processing logic.

Now if Authorization server can't able to process a request in stipulated time, then I want to close the goroutine from memory.

Here is what I tried:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequest("GET", authorizationServer, nil)
req.Header = r.Header
req.WithContext(ctx)
res, error := client.Do(req)
select {
case <-time.After(10 * time.Second):
    fmt.Println("overslept")
case <-ctx.Done():
    fmt.Println(ctx.Err()) // prints "context deadline exceeded"
}

Over here, context returns as "deadline exceeded", if request is not processed in stipulated time. But It continues to process that request and return response in more that specified time. So How can I stop request flow(goroutine), when time exceeded.

Although I've also implemented complete request needs to be processed in 60 seconds with this code:

var netTransport = &http.Transport{
    Dial: (&net.Dialer{
        Timeout: 60 * time.Second,
    }).Dial,
    TLSHandshakeTimeout: 60 * time.Second,
}
client := &http.Client{
    Timeout:   time.Second * 60,
    Transport: netTransport,
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
        return http.ErrUseLastResponse
    },
}

So do I need any seperate context implementations as well? Thanks in advance for help.

Note1: It will be awesome, If we can manage timeout on every requests(goroutine) created by HTTP server, using context.

  • 写回答

1条回答 默认 最新

  • dpps0715 2017-04-10 11:47
    关注

    What happens in your code is very correct and behaves as expected.

    You create a context with 5 seconds timeout. You pass it to the request and make that request. Let's say that request returns in 2 seconds. You then do a select and either wait 10 seconds or wait for the context to finish. Context will always finish in the initial 5 seconds from when it was created and will also give that error every time it reaches the end.

    The context is independent of the request and it will reach it's deadline unless, cancelled previously. You cancel the request when the function finishes using defer.

    In your code the request takes your timeout in consideration. But the ctx.Err() will return deadline exceeded everytime it reaches the timeout. Since that's what happens inside the context. calling ctx.Err() multiple times will return the same error.

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    go func () {
        select {
        case <-time.After(10 * time.Second):
            fmt.Println("overslept")
        case <-ctx.Done():
            fmt.Println(ctx.Err()) // prints "context deadline exceeded"
        }
    }()
    req, _ := http.NewRequest("GET", authorizationServer, nil)
    req.Header = r.Header
    req = req.WithContext(ctx)
    res, error := client.Do(req)
    

    From the context documentation:

    // Err returns a non-nil error value after Done is closed. Err returns
    // Canceled if the context was canceled or DeadlineExceeded if the
    // context's deadline passed. No other values for Err are defined.
    // After Done is closed, successive calls to Err return the same value.
    

    In your code, the timeout will always be reached and not cancelled, that is why you receive DeadlineExceeeded. Your code is correct except the select part which will block until either 10 seconds pass or context timeout is reached. In your case always the context timeout is reached.

    You should check the error returned by the client.Do call and not worry about the context error in here. You are the one controlling the context. If the request timeouts, a case you should test of course, then a proper error would be returned for you to verify.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 为什么我写出来的绘图程序是这样的,有没有lao哥改一下
  • ¥15 js,页面2返回页面1时定位进入的设备
  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥15 绘制多分类任务的roc曲线时只画出了一类的roc,其它的auc显示为nan
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败