Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bigquery): augment retry predicate to support additional errors #4046

Merged
merged 3 commits into from May 3, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 28 additions & 7 deletions bigquery/bigquery.go
Expand Up @@ -19,6 +19,8 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"

"cloud.google.com/go/internal"
Expand Down Expand Up @@ -177,13 +179,32 @@ func retryableError(err error) bool {
if err.Error() == "http2: stream closed" {
return true
}
e, ok := err.(*googleapi.Error)
if !ok {
return false

switch e := err.(type) {
case *googleapi.Error:
// We received a structured error from backend.
var reason string
if len(e.Errors) > 0 {
reason = e.Errors[0].Reason
}
if e.Code == http.StatusServiceUnavailable || e.Code == http.StatusBadGateway || reason == "backendError" || reason == "rateLimitExceeded" {
return true
}
case *url.Error:
retryable := []string{"connection refused", "connection reset"}
for _, s := range retryable {
if strings.Contains(e.Error(), s) {
return true
}
}
case interface{ Temporary() bool }:
if e.Temporary() {
return true
}
}
var reason string
if len(e.Errors) > 0 {
reason = e.Errors[0].Reason
// Unwrap is only supported in go1.13.x+
if e, ok := err.(interface{ Unwrap() error }); ok {
codyoss marked this conversation as resolved.
Show resolved Hide resolved
return retryableError(e.Unwrap())
}
return e.Code == http.StatusServiceUnavailable || e.Code == http.StatusBadGateway || reason == "backendError" || reason == "rateLimitExceeded"
return false
}
28 changes: 28 additions & 0 deletions bigquery/bigquery_test.go
Expand Up @@ -17,8 +17,10 @@ package bigquery
import (
"errors"
"net/http"
"net/url"
"testing"

"golang.org/x/xerrors"
"google.golang.org/api/googleapi"
)

Expand Down Expand Up @@ -46,6 +48,32 @@ func TestRetryableErrors(t *testing.T) {
},
true,
},
{
"url connection error",
&url.Error{Op: "blah", URL: "blah", Err: errors.New("connection refused")},
true,
},
{
"url other error",
&url.Error{Op: "blah", URL: "blah", Err: errors.New("blah")},
false,
},
{
"wrapped retryable",
xerrors.Errorf("test of wrapped retryable: %w", &googleapi.Error{
Code: http.StatusServiceUnavailable,
Message: "foo",
Errors: []googleapi.ErrorItem{
{Reason: "backendError", Message: "foo"},
},
}),
true,
},
{
"wrapped non-retryable",
xerrors.Errorf("test of wrapped retryable: %w", errors.New("blah")),
false,
},
{
// not retried per https://google.aip.dev/194
"internal error",
Expand Down
1 change: 1 addition & 0 deletions bigquery/go.mod
Expand Up @@ -8,6 +8,7 @@ require (
github.com/golang/protobuf v1.5.2
github.com/google/go-cmp v0.5.5
github.com/googleapis/gax-go/v2 v2.0.5
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
google.golang.org/api v0.46.0
google.golang.org/genproto v0.0.0-20210503173045-b96a97608f20
google.golang.org/grpc v1.37.0
Expand Down