Home > front end >  Handling errors following net packet read timeout
Handling errors following net packet read timeout

Time:06-16

I am using the conn.SetReadDeadline method to set the read timeout for conn, When conn.Read waits for more than the specified time, it will return and return an error of type *net.OpError. This error is returned by the net package after wrapping all non-io.EOF errors.

I can get the error before wrapping with Unwrap(). A timeout error is an error of type *poll.DeadlineExceededError. I use statements like this in my code to handle timeout errors precisely.

import "internal/poll"

_, err = conn.Read(p)

    if err != nil {
        if pe, ok := err.(*net.OpError); ok {
            err = pe.Unwrap()
            if timeout, ok := err.(*poll.DeadlineExceededError); ok {
                log.Error(fmt.Sprintf("%T, %s", timeout, timeout))
            }
        }
        return
    }

I received an use of internal package internal/poll not allowed error while running the program. The compiler tells me that internal packages cannot be used.

I googled and found a solution to delete the internal folder, is this the final solution? Will there be a better solution?

CodePudding user response:

The os package exports that error as os.ErrDeadlineExceeded (check the source code). You can try :

if errors.Is(err, os.ErrDeadlineExceeded) {
    log.Error("Timeout error")
}

[edit] actually, after reading @Brit's comment, this is the documented way to check for that error. See the doc for Conn.SetDeadline() :

If the deadline is exceeded a call to Read or Write or to other I/O methods will return an error that wraps os.ErrDeadlineExceeded. This can be tested using errors.Is(err, os.ErrDeadlineExceeded).


Another indication that an error is a "timeout" error is if it has a Timeout() bool method, which returns true when called.

This is part of the net.Error interface (although this interface has an extra method, which is documented as deprecated), and implemented by the net.OpError type (and also by the internal poll.DeadlineExceededError type).

There are several functions (net.OpError.IsTimeout(), os.SyscallError.IsTimeout() and the public function os.IsTimeout() for example) that implement a timeout checking by directly casting the error value to a timeout interface.

If you want to deal with errors that can be wrapped one into another, you may want to implement your own isTimeout() check using errors.As(...) :

// isTimeout : use errors.As() to unwrap errors and check if a sub error is a Timeout error
func isTimeout(err error) bool {
    var terr interface{ Timeout() bool }
    return errors.As(err, &terr) && terr.Timeout()
}

https://go.dev/play/p/OhhKY3XsGjZ

note that :

the difference between the isTimeout() function above and the errors.Is(err, os.ErrDeadlineExceeded) call is that the latter will try to match exacly an ErrDeadlineExceeded (which is mostly triggered by setting SetDeadline() on some file-or-conn-like object), while the latter one may return true for errors that try to advertise "I'm a timeout error" for other reasons (e.g : an HTTP "408 Request timeout" response)


note : all links above refer to go 1.18.3 . Depending on the version of go you are using, you may have to adapt some of the code above (for example : the os.ErrDeadlineExceeded was added in go1.15 )

  •  Tags:  
  • go
  • Related