Here is my observation I have multiple fqdn configured and will try to reach it one by one but only one will respond http2 response and others will fail. I have configured clientTimeout 2s in http.Client and will try first fqdn which will not be resolved in my app to ip and port so request tried with fqdn and port but http2 request takes 4s second to timeout instead of 2s.. I am unable to understand the logic behind it why clientTimeout is discarded. Please share the details or any reference
Can you please share some code that shows what you have tried?
There are many timeouts involved in an HTTP-Request. For example DNS-query happens first to resolve the host name, this can already take a while to complete. After that first a TLS-Handshake needs to be established (including cipher-negotiation, certificate validation, optional revocation check), following this there could be HTTP-redirects or protocol switches (like establishing a websocket) and then finally the actual http-request starts with writing headers, writing body and reading the reply.
There are various timeouts for all stages of this complex process and it’s not easy to combine the right timeouts for your use-case.
If you just want a “end-to-end” timeout for your whole function call, you should probably use a context.WithTimeout() and pass that to your calls, this will stop after your timeout, no matter in which step the process currently is.
Thanks for the reply
I have setup only clientTimeout using below and sent request.. After using contextTimeout I am able to achieve 2s exit.. still with clientTimeout code should have exited
client := &http.Client{
CheckRedirect: func(req \*http.Request, via \[\]\*http.Request) error {
return http.ErrUseLastResponse // Stops http stack redirect
},
Transport: &http2.Transport{
AllowHTTP: true,
DialTLS: func(network, addr string, cfg \*tls.Config) (net.Conn, error) {
return net.DialTimeout(network, addr, (2000)\*time.Millisecond)
},
PingTimeout: 2000 \* time.Millisecond,
ReadIdleTimeout: 2000 \* time.Millisecond,
},
Timeout: 2000 \* time.Millisecond,
}
postReq, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
resp, err := client.Do(postReq)
if err != nil {
if err, ok := err.(net.Error); ok && (err.Timeout() || strings.Contains(err.Error(), cc.CONN_REFUSED)) {
return resp, err, true
}
return resp, err, false
}
with timeout code
timeout := 2 * time.Second // or whatever you need per request
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
// handle error constructing request
}
resp, err := client.Do(req)
if err != nil {
// context deadline exceeded will land here
if ne, ok := err.(net.Error); ok && ne.Timeout() {
// timed out
}
return resp, err, false
}