...
1
2
3
4
5 package gensupport
6
7 import (
8 "errors"
9 "io"
10 "net"
11 "strings"
12 "time"
13
14 "github.com/googleapis/gax-go/v2"
15 "google.golang.org/api/googleapi"
16 )
17
18
19
20 type Backoff interface {
21 Pause() time.Duration
22 }
23
24
25 var (
26
27 defaultRetryDeadline = 32 * time.Second
28
29 backoff = func() Backoff {
30 return &gax.Backoff{Initial: 100 * time.Millisecond}
31 }
32
33 syscallRetryable func(error) bool = func(err error) bool { return false }
34 )
35
36 const (
37
38
39
40
41 statusTooManyRequests = 429
42
43
44
45 statusRequestTimeout = 408
46 )
47
48
49
50
51
52 func shouldRetry(status int, err error) bool {
53 if 500 <= status && status <= 599 {
54 return true
55 }
56 if status == statusTooManyRequests || status == statusRequestTimeout {
57 return true
58 }
59 if err == io.ErrUnexpectedEOF {
60 return true
61 }
62
63 if syscallRetryable(err) {
64 return true
65 }
66 if err, ok := err.(interface{ Temporary() bool }); ok {
67 if err.Temporary() {
68 return true
69 }
70 }
71 var opErr *net.OpError
72 if errors.As(err, &opErr) {
73 if strings.Contains(opErr.Error(), "use of closed network connection") {
74
75 return true
76 }
77 }
78
79
80
81 if err, ok := err.(interface{ Unwrap() error }); ok {
82 return shouldRetry(status, err.Unwrap())
83 }
84 return false
85 }
86
87
88 type RetryConfig struct {
89 Backoff *gax.Backoff
90 ShouldRetry func(err error) bool
91 }
92
93
94 func (r *RetryConfig) backoff() Backoff {
95 if r == nil || r.Backoff == nil {
96 return backoff()
97 }
98 return &gax.Backoff{
99 Initial: r.Backoff.Initial,
100 Max: r.Backoff.Max,
101 Multiplier: r.Backoff.Multiplier,
102 }
103 }
104
105
106
107
108
109
110
111 func (r *RetryConfig) errorFunc() func(status int, err error) bool {
112 if r == nil || r.ShouldRetry == nil {
113 return shouldRetry
114 }
115 return func(status int, err error) bool {
116 if status >= 400 {
117 return r.ShouldRetry(&googleapi.Error{Code: status})
118 }
119 return r.ShouldRetry(err)
120 }
121 }
122
View as plain text