fserrors: make http2 "server sent GOAWAY" a retriable error - fixes #9664
When an HTTP/2 server retires a connection with GOAWAY after it has
already sent successful response headers, Go's http2 transport fails the
read of the response body with
http2: server sent GOAWAY and closed the connection; LastStreamID=..., ErrCode=NO_ERROR, debug=""
This was not recognised as a retriable networking error, so a transient
connection retirement aborted the whole command instead of consuming a
low level retry. It was reported against a large S3 check, where an
interrupted ListObjectsV2 page made rclone report destination objects as
missing and exit unsuccessfully.
The concrete error type is unexported by net/http, so match on the
message as we already do for the other http2 transport errors.
This commit is contained in:
@@ -386,6 +386,7 @@ var retriableErrorStrings = []string{
|
||||
"server closed idle connection", // net/http/transport.go
|
||||
"bad record MAC", // crypto/tls/alert.go
|
||||
"stream error:", // net/http/h2_bundle.go
|
||||
"http2: server sent GOAWAY", // net/http/h2_bundle.go
|
||||
"tls: use of closed connection", // crypto/tls/conn.go
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ func wrap(err error, message string) error {
|
||||
|
||||
var errUseOfClosedNetworkConnection = errors.New("use of closed network connection")
|
||||
|
||||
var errHTTP2GoAway = errors.New(`http2: server sent GOAWAY and closed the connection; LastStreamID=19999, ErrCode=NO_ERROR, debug=""`)
|
||||
|
||||
type myError1 struct {
|
||||
Err error
|
||||
}
|
||||
@@ -135,6 +137,8 @@ func TestShouldRetry(t *testing.T) {
|
||||
{&url.Error{Op: "post", URL: "/", Err: io.EOF}, true},
|
||||
{&url.Error{Op: "post", URL: "/", Err: errUseOfClosedNetworkConnection}, true},
|
||||
{&url.Error{Op: "post", URL: "/", Err: fmt.Errorf("net/http: HTTP/1.x transport connection broken: %v", fmt.Errorf("http: ContentLength=%d with Body length %d", 100663336, 99590598))}, true},
|
||||
{errHTTP2GoAway, true},
|
||||
{fmt.Errorf("operation error S3: ListObjectsV2, deserialization failed, failed to decode response body: %w", errHTTP2GoAway), true},
|
||||
} {
|
||||
got := ShouldRetry(test.err)
|
||||
assert.Equal(t, test.want, got, fmt.Sprintf("test #%d: %v", i, test.err))
|
||||
|
||||
Reference in New Issue
Block a user