Skip to content

Commit

Permalink
feat(storage): add net.ErrClosed to default retry (#5384)
Browse files Browse the repository at this point in the history

Co-authored-by: Chris Cotter <cjcotter@google.com>
  • Loading branch information
BrennaEpp and tritone committed Jan 25, 2022
1 parent 0ea8993 commit a4801c7
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
12 changes: 10 additions & 2 deletions storage/invoke.go
Expand Up @@ -17,11 +17,13 @@ package storage
import (
"context"
"io"
"net"
"net/url"
"strings"

"cloud.google.com/go/internal"
gax "github.com/googleapis/gax-go/v2"
"golang.org/x/xerrors"
"google.golang.org/api/googleapi"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -59,16 +61,22 @@ func shouldRetry(err error) bool {
if err == nil {
return false
}
if err == io.ErrUnexpectedEOF {
if xerrors.Is(err, io.ErrUnexpectedEOF) {
return true
}

switch e := err.(type) {
case *net.OpError:
if strings.Contains(e.Error(), "use of closed network connection") {
// TODO: check against net.ErrClosed (go 1.16+) instead of string
return true
}
case *googleapi.Error:
// Retry on 408, 429, and 5xx, according to
// https://cloud.google.com/storage/docs/exponential-backoff.
return e.Code == 408 || e.Code == 429 || (e.Code >= 500 && e.Code < 600)
case *url.Error:
// Retry socket-level errors ECONNREFUSED and ENETUNREACH (from syscall).
// Retry socket-level errors ECONNREFUSED and ECONNRESET (from syscall).
// Unfortunately the error type is unexported, so we resort to string
// matching.
retriable := []string{"connection refused", "connection reset"}
Expand Down
7 changes: 7 additions & 0 deletions storage/invoke_test.go
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"errors"
"io"
"net"
"net/url"
"testing"

Expand Down Expand Up @@ -263,6 +264,12 @@ func TestShouldRetry(t *testing.T) {
inputErr: status.Error(codes.PermissionDenied, "non-retryable gRPC error"),
shouldRetry: false,
},
{
desc: "wrapped ErrClosed text",
// TODO: check directly against wrapped net.ErrClosed (go 1.16+)
inputErr: &net.OpError{Op: "write", Err: errors.New("use of closed network connection")},
shouldRetry: true,
},
} {
t.Run(test.desc, func(s *testing.T) {
got := shouldRetry(test.inputErr)
Expand Down

0 comments on commit a4801c7

Please sign in to comment.