Retry errors which indicate the connection closed prematurely.

See discussion in #442
This commit is contained in:
Nick Craig-Wood 2016-04-29 16:42:08 +01:00
parent 5c2d8ffe33
commit 1752ee3c8b
4 changed files with 64 additions and 4 deletions

View file

@ -4,8 +4,10 @@ package fs
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
)
// Retry is an optional interface for error as to whether the
@ -56,14 +58,39 @@ func RetryError(err error) error {
return plainRetryError{err}
}
// isClosedConnError reports whether err is an error from use of a closed
// network connection.
//
// Code adapted from net/http
func isClosedConnError(err error) bool {
if err == nil {
return false
}
// Note that this error isn't exported so we have to do a
// string comparison :-(
str := err.Error()
if strings.Contains(str, "use of closed network connection") {
return true
}
return isClosedConnErrorPlatform(err)
}
// ShouldRetry looks at an error and tries to work out if retrying the
// operation that caused it would be a good idea. It returns true if
// the error implements Timeout() or Temporary() and it returns true.
// the error implements Timeout() or Temporary() or if the error
// indicates a premature closing of the connection.
func ShouldRetry(err error) bool {
if err == nil {
return false
}
// Look for premature closing of connection
if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) {
return true
}
// Unwrap url.Error
if urlErr, ok := err.(*url.Error); ok {
err = urlErr.Err