@@ -16,9 +16,13 @@ package storage
16
16
17
17
import (
18
18
"context"
19
+ "io"
20
+ "net/url"
21
+ "strings"
19
22
20
23
"cloud.google.com/go/internal"
21
24
gax "github.com/googleapis/gax-go/v2"
25
+ "google.golang.org/api/googleapi"
22
26
)
23
27
24
28
// runWithRetry calls the function until it returns nil or a non-retryable error, or
@@ -35,3 +39,34 @@ func runWithRetry(ctx context.Context, call func() error) error {
35
39
return true , err
36
40
})
37
41
}
42
+
43
+ func shouldRetry (err error ) bool {
44
+ if err == io .ErrUnexpectedEOF {
45
+ return true
46
+ }
47
+ switch e := err .(type ) {
48
+ case * googleapi.Error :
49
+ // Retry on 429 and 5xx, according to
50
+ // https://cloud.google.com/storage/docs/exponential-backoff.
51
+ return e .Code == 429 || (e .Code >= 500 && e .Code < 600 )
52
+ case * url.Error :
53
+ // Retry socket-level errors ECONNREFUSED and ENETUNREACH (from syscall).
54
+ // Unfortunately the error type is unexported, so we resort to string
55
+ // matching.
56
+ retriable := []string {"connection refused" , "connection reset" }
57
+ for _ , s := range retriable {
58
+ if strings .Contains (e .Error (), s ) {
59
+ return true
60
+ }
61
+ }
62
+ case interface { Temporary () bool }:
63
+ if e .Temporary () {
64
+ return true
65
+ }
66
+ }
67
+ // Unwrap is only supported in go1.13.x+
68
+ if e , ok := err .(interface { Unwrap () error }); ok {
69
+ return shouldRetry (e .Unwrap ())
70
+ }
71
+ return false
72
+ }
0 commit comments