Handling errors following net packet read timeout

Issue

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?

Solution

The os package exports that error as os.ErrDeadlineExceeded. You can try :

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

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

Answered By – LeGEC

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.