I'm sending a request with a context which specified with a 10 seconds timeout:
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10)
defer cancel()
_, err := client.SendRequest(ctx)
if err != nil {
return 0, err
}
now when I hit that timeout the error message is confusing:
context deadline exceeded
Is it possible to check if the err is the timeout error so that I can print a nicer error message?
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10)
defer cancel()
_, err := client.SendRequest(ctx)
if err != nil {
if isTimeoutError(err) {
return nil, fmt.Errorf("the request is timeout after 10 seconds")
}
return nil, err
}
How to implement such isTimeoutError
function?
This error is caused by a communication failure on the server side. This error is returned in a HTTP message with a 500 status code, indicating that the problem was on the server rather than in the data you sent. If you get this error you should resend your request.
The error 'context deadline exceeded' means that we ran into a situation where a given action was not completed in an expected timeframe. For Vault this is typically going to be related to a network connection made to an external system such as a database or even a storage backend such as Consul.
Context deadline exceededOpen a new connection. Perform TLS handshake using the new connection. Optionally, pass some authentication checks, for example, using Redis AUTH command.
When a Context is canceled, all Contexts derived from it are also canceled. The WithCancel, WithDeadline, and WithTimeout functions take a Context (the parent) and return a derived Context (the child) and a CancelFunc.
The cleanest way to do this in Go 1.13+ is using the new errors.Is
function.
// Create a context with a very short timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
defer cancel()
// Create the request with it
r, _ := http.NewRequest("GET", "http://example.com", nil)
r = r.WithContext(ctx)
// Do it, it will fail because the request will take longer than 1ms
_, err := http.DefaultClient.Do(r)
log.Println(err) // Get http://example.com: context deadline exceeded
// This prints false, because the http client wraps the context.DeadlineExceeded
// error into another one with extra information.
log.Println(err == context.DeadlineExceeded)
// This prints true, because errors.Is checks all the errors in the wrap chain,
// and returns true if any of them matches.
log.Println(errors.Is(err, context.DeadlineExceeded))
You can determine if an error is the result of a context timeout by comparing the error to context.DeadlineExceeded:
if err == context.DeadlineExceeded {
// context deadline exceeded
}
You can determine if an error is any timeout error using the following function:
func isTimeoutError(err error) bool {
e, ok := err.(net.Error)
return ok && e.Timeout()
}
This function returns true all timeout errors including the value context.DeadlineExceeded
. That value satisfies the net.Error
interface and has a Timeout
method that always returns true
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With