I use the following to check for timeouts when calling a webservice, but I would like to check specifically if there is a timeout error returned. How do I do that :S
I have this:
// Timeout
type Timeout struct {
Connect time.Duration
ReadWrite time.Duration
}
// TimeoutDialer
func TimeoutDialer(timeout *Timeout) func(net, addr string) (c net.Conn, err error) {
return func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, timeout.Connect)
if err != nil {
return nil, err
}
conn.SetDeadline(time.Now().Add(timeout.ReadWrite))
return conn, nil
}
}
// HttpClient
func HttpClient(config Config) *http.Client {
to := &Timeout{
Connect: time.Duration(config.MaxWait) * time.Second,
ReadWrite: time.Duration(config.MaxWait) * time.Second,
}
return &http.Client{
Transport: &http.Transport{
Dial: TimeoutDialer(to),
},
}
}
As of go1.6, all errors from timeouts should conform to net.Error
with Timeout()
set properly. All you need to check for is:
if err, ok := err.(net.Error); ok && err.Timeout() {
In older versions, checking for timeout through the http package was more difficult.
- You can get a
*net.OpError
with Timeout() if you hit a Deadline set on the underlying connection.
- You can get a
tlsHandshakeTimeoutError
(which is obviously not exported) that implements the net.Error
interface.
- You can get a
url.Error
, if there was a problem within the url package (timeout during initial connection)
- You can get an error with "use of closed network connection" if you hit a timeout set with
http.Client.Timeout
[go1.3+] (which calls Transport.CancelRequest
). As of go1.5, this will have the Timeout property set correctly.
You could check for a net.Error
with a type switch:
switch err := err.(type) {
case net.Error:
if err.Timeout() {
fmt.Println("This was a net.Error with a Timeout")
}
case *url.Error:
fmt.Println("This is a *url.Error")
if err, ok := err.Err.(net.Error); ok && err.Timeout() {
fmt.Println("and it was because of a timeout")
}
}
With go < 1.5 you will need to check the error string for an http.Client
timeout:
if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
fmt.Println("Could be from a Transport.CancelRequest")
}
You want the net.Error
interface. http://golang.org/pkg/net/#Error
if e,ok := err.(net.Error); ok && e.Timeout() {
// This was a timeout
} else if err != nil {
// This was an error, but not a timeout
}
Note that the type assertion err.(net.Error)
will correctly handle the nil
case and return false for the ok
value if nil
is returned as the error, short-circuiting the Timeout
check.