Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if an error is "deadline exceeded" error?

Tags:

go

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?

like image 594
Leo Zhang Avatar asked May 11 '19 01:05

Leo Zhang


People also ask

What is deadline exceeded error?

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.

Would you exceed context deadline?

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.

How do you avoid context deadline exceeded?

Context deadline exceededOpen a new connection. Perform TLS handshake using the new connection. Optionally, pass some authentication checks, for example, using Redis AUTH command.

What is context canceled Golang?

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.


2 Answers

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))
like image 76
Dirbaio Avatar answered Oct 14 '22 09:10

Dirbaio


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.

like image 40
Bayta Darell Avatar answered Oct 14 '22 10:10

Bayta Darell