23

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?

1
  • 1
    The Timeout field pre-dates contexts and applies to all requests made by the client. Commented Sep 30, 2020 at 13:10

2 Answers 2

26

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 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

Sign up to request clarification or add additional context in comments.

1 Comment

We recently came across this in our project where the Client Timeout was taking over since it was smaller than context timeout. Just in case you want to capture this error and handle specifically, asserting with Deadline Exceeded Error wont work for Client timing out. You can try os.Timeout method, which would work for both Client and context timeout.
4

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.