Skip to content

Commit 0da9ab0

Browse files
authored
feat(storage): export ShouldRetry (#6370)
Export the default func to determine whether an error is retryable. This makes it easier for users to use the WithErrorFunc option without copying a lot of code. Fixes #6362
1 parent 3726570 commit 0da9ab0

File tree

5 files changed

+34
-24
lines changed

5 files changed

+34
-24
lines changed

storage/grpc_client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,7 +1379,7 @@ func (r *gRPCReader) Close() error {
13791379
// an attempt to reopen the stream.
13801380
func (r *gRPCReader) recv() (*storagepb.ReadObjectResponse, error) {
13811381
msg, err := r.stream.Recv()
1382-
if err != nil && shouldRetry(err) {
1382+
if err != nil && ShouldRetry(err) {
13831383
// This will "close" the existing stream and immediately attempt to
13841384
// reopen the stream, but will backoff if further attempts are necessary.
13851385
// Reopening the stream Recvs the first message, so if retrying is
@@ -1559,7 +1559,7 @@ func (w *gRPCWriter) uploadBuffer(recvd int, start int64, doneReading bool) (*st
15591559
// resend the entire buffer via a new stream.
15601560
// If not retriable, falling through will return the error received
15611561
// from closing the stream.
1562-
if shouldRetry(err) {
1562+
if ShouldRetry(err) {
15631563
sent = 0
15641564
finishWrite = false
15651565
// TODO: Add test case for failure modes of querying progress.
@@ -1590,7 +1590,7 @@ func (w *gRPCWriter) uploadBuffer(recvd int, start int64, doneReading bool) (*st
15901590
// resend the entire buffer via a new stream.
15911591
// If not retriable, falling through will return the error received
15921592
// from closing the stream.
1593-
if shouldRetry(err) {
1593+
if ShouldRetry(err) {
15941594
sent = 0
15951595
finishWrite = false
15961596
offset, err = w.determineOffset(start)

storage/invoke.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func run(ctx context.Context, call func() error, retry *retryConfig, isIdempoten
5757
bo.Initial = retry.backoff.Initial
5858
bo.Max = retry.backoff.Max
5959
}
60-
var errorFunc func(err error) bool = shouldRetry
60+
var errorFunc func(err error) bool = ShouldRetry
6161
if retry.shouldRetry != nil {
6262
errorFunc = retry.shouldRetry
6363
}
@@ -89,7 +89,16 @@ func setRetryHeaderGRPC(_ context.Context) func(string, int) {
8989
}
9090
}
9191

92-
func shouldRetry(err error) bool {
92+
// ShouldRetry returns true if an error is retryable, based on best practice
93+
// guidance from GCS. See
94+
// https://cloud.google.com/storage/docs/retry-strategy#go for more information
95+
// on what errors are considered retryable.
96+
//
97+
// If you would like to customize retryable errors, use the WithErrorFunc to
98+
// supply a RetryOption to your library calls. For example, to retry additional
99+
// errors, you can write a custom func that wraps ShouldRetry and also specifies
100+
// additional errors that should return true.
101+
func ShouldRetry(err error) bool {
93102
if err == nil {
94103
return false
95104
}
@@ -131,7 +140,7 @@ func shouldRetry(err error) bool {
131140
}
132141
// Unwrap is only supported in go1.13.x+
133142
if e, ok := err.(interface{ Unwrap() error }); ok {
134-
return shouldRetry(e.Unwrap())
143+
return ShouldRetry(e.Unwrap())
135144
}
136145
return false
137146
}

storage/invoke_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ func TestShouldRetry(t *testing.T) {
306306
},
307307
} {
308308
t.Run(test.desc, func(s *testing.T) {
309-
got := shouldRetry(test.inputErr)
309+
got := ShouldRetry(test.inputErr)
310310

311311
if got != test.shouldRetry {
312312
s.Errorf("got %v, want %v", got, test.shouldRetry)

storage/storage.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,8 +1875,8 @@ func (ws *withPolicy) apply(config *retryConfig) {
18751875

18761876
// WithErrorFunc allows users to pass a custom function to the retryer. Errors
18771877
// will be retried if and only if `shouldRetry(err)` returns true.
1878-
// By default, the following errors are retried (see invoke.go for the default
1879-
// shouldRetry function):
1878+
// By default, the following errors are retried (see ShouldRetry for the default
1879+
// function):
18801880
//
18811881
// - HTTP responses with codes 408, 429, 502, 503, and 504.
18821882
//
@@ -1887,7 +1887,8 @@ func (ws *withPolicy) apply(config *retryConfig) {
18871887
// - Wrapped versions of these errors.
18881888
//
18891889
// This option can be used to retry on a different set of errors than the
1890-
// default.
1890+
// default. Users can use the default ShouldRetry function inside their custom
1891+
// function if they only want to make minor modifications to default behavior.
18911892
func WithErrorFunc(shouldRetry func(err error) bool) RetryOption {
18921893
return &withErrorFunc{
18931894
shouldRetry: shouldRetry,

storage/storage_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,10 +1139,10 @@ func TestRetryer(t *testing.T) {
11391139
name: "object retryer configures retry",
11401140
objectOptions: []RetryOption{
11411141
WithPolicy(RetryAlways),
1142-
WithErrorFunc(shouldRetry),
1142+
WithErrorFunc(ShouldRetry),
11431143
},
11441144
want: &retryConfig{
1145-
shouldRetry: shouldRetry,
1145+
shouldRetry: ShouldRetry,
11461146
policy: RetryAlways,
11471147
},
11481148
},
@@ -1155,15 +1155,15 @@ func TestRetryer(t *testing.T) {
11551155
Multiplier: 6,
11561156
}),
11571157
WithPolicy(RetryAlways),
1158-
WithErrorFunc(shouldRetry),
1158+
WithErrorFunc(ShouldRetry),
11591159
},
11601160
want: &retryConfig{
11611161
backoff: &gax.Backoff{
11621162
Initial: time.Minute,
11631163
Max: time.Hour,
11641164
Multiplier: 6,
11651165
},
1166-
shouldRetry: shouldRetry,
1166+
shouldRetry: ShouldRetry,
11671167
policy: RetryAlways,
11681168
},
11691169
},
@@ -1176,15 +1176,15 @@ func TestRetryer(t *testing.T) {
11761176
Multiplier: 6,
11771177
}),
11781178
WithPolicy(RetryAlways),
1179-
WithErrorFunc(shouldRetry),
1179+
WithErrorFunc(ShouldRetry),
11801180
},
11811181
want: &retryConfig{
11821182
backoff: &gax.Backoff{
11831183
Initial: time.Minute,
11841184
Max: time.Hour,
11851185
Multiplier: 6,
11861186
},
1187-
shouldRetry: shouldRetry,
1187+
shouldRetry: ShouldRetry,
11881188
policy: RetryAlways,
11891189
},
11901190
},
@@ -1195,11 +1195,11 @@ func TestRetryer(t *testing.T) {
11951195
},
11961196
objectOptions: []RetryOption{
11971197
WithPolicy(RetryNever),
1198-
WithErrorFunc(shouldRetry),
1198+
WithErrorFunc(ShouldRetry),
11991199
},
12001200
want: &retryConfig{
12011201
policy: RetryNever,
1202-
shouldRetry: shouldRetry,
1202+
shouldRetry: ShouldRetry,
12031203
},
12041204
},
12051205
{
@@ -1209,11 +1209,11 @@ func TestRetryer(t *testing.T) {
12091209
},
12101210
objectOptions: []RetryOption{
12111211
WithPolicy(RetryNever),
1212-
WithErrorFunc(shouldRetry),
1212+
WithErrorFunc(ShouldRetry),
12131213
},
12141214
want: &retryConfig{
12151215
policy: RetryNever,
1216-
shouldRetry: shouldRetry,
1216+
shouldRetry: ShouldRetry,
12171217
},
12181218
},
12191219
{
@@ -1231,11 +1231,11 @@ func TestRetryer(t *testing.T) {
12311231
Initial: time.Nanosecond,
12321232
Max: time.Microsecond,
12331233
}),
1234-
WithErrorFunc(shouldRetry),
1234+
WithErrorFunc(ShouldRetry),
12351235
},
12361236
want: &retryConfig{
12371237
policy: RetryAlways,
1238-
shouldRetry: shouldRetry,
1238+
shouldRetry: ShouldRetry,
12391239
backoff: &gax.Backoff{
12401240
Initial: time.Nanosecond,
12411241
Max: time.Microsecond,
@@ -1268,7 +1268,7 @@ func TestRetryer(t *testing.T) {
12681268
name: "object retryer does not override bucket retryer if option is not set",
12691269
bucketOptions: []RetryOption{
12701270
WithPolicy(RetryNever),
1271-
WithErrorFunc(shouldRetry),
1271+
WithErrorFunc(ShouldRetry),
12721272
},
12731273
objectOptions: []RetryOption{
12741274
WithBackoff(gax.Backoff{
@@ -1278,7 +1278,7 @@ func TestRetryer(t *testing.T) {
12781278
},
12791279
want: &retryConfig{
12801280
policy: RetryNever,
1281-
shouldRetry: shouldRetry,
1281+
shouldRetry: ShouldRetry,
12821282
backoff: &gax.Backoff{
12831283
Initial: time.Nanosecond,
12841284
Max: time.Second,

0 commit comments

Comments
 (0)