Go http client timeout vs context timeout

20k views Asked by At

What's the difference between timeout set in http.Client and timeout set in request's context?

I've seen 2 ways of setting timeout in http client.

First:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:8080", nil)

Second:

client := http.Client{
    Timeout: 2 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
    panic(err)
}

when to use one over the other?

2

There are 2 answers

0
mfathirirhas On BEST ANSWER

Both can achieve the same thing which is to terminate the request due to timeout.

But using context is the preferred way as it's made for this task. The field timeout exist before context added to Go. You have to pick one for timeout at the time creating the request as the the request will pick the smaller timeout to be applied, rendering other useless. In this case the preferable method is using the context timeout as you have more control over it, you can use cancel without specifying timeout in case you want to cancel the request by logic decision. Using context you can also pass any values through it describing request scope values.

Using context is request specific, while using the Client timeout might be applied to all request pass to Do method client has. If you want to specialise your deadline/timeout to each request then use context, otherwise if you want 1 timeout for every outbound request then using client timeout is enough.

You can also read about it here Specify timeout when tracing HTTP request in Go

0
Shubham Srivastava On

Normally we would use this method when we only want to put a timeout for a http request only

client := http.Client{
    Timeout: 2 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
    panic(err)
}

I think the question is when should we be using contexts, if you go to documentation you will find

Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.

So lets say you have a API that needs to respond in under some time and you need a way to track all go routines it creates and want to signal them all at the same time to stop; this is the use case where it makes sense to use a context and pass it to all the go routines created by one API call and it becomes really easy to know when the context expired and when everyone needs to stop working.

Although The way you do http request will work but it does not make much sense that you create a context that is explicit to a particular request unless lets say your request is run in a goroutine and you need to pass a cancel signal due to some other inputs you received after executing it.

Ideally in most circumstances context is used to scope a chain of requests/ goroutines you need to signal.

You should read this for more clarity of when to use context https://blog.golang.org/context