diff options
Diffstat (limited to 'vendor/google.golang.org/api/gensupport/retry.go')
-rw-r--r-- | vendor/google.golang.org/api/gensupport/retry.go | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/vendor/google.golang.org/api/gensupport/retry.go b/vendor/google.golang.org/api/gensupport/retry.go new file mode 100644 index 0000000..fdde3f4 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/retry.go | |||
@@ -0,0 +1,84 @@ | |||
1 | // Copyright 2017 Google LLC | ||
2 | // | ||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | // you may not use this file except in compliance with the License. | ||
5 | // You may obtain a copy of the License at | ||
6 | // | ||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | // | ||
9 | // Unless required by applicable law or agreed to in writing, software | ||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | // See the License for the specific language governing permissions and | ||
13 | // limitations under the License. | ||
14 | |||
15 | package gensupport | ||
16 | |||
17 | import ( | ||
18 | "context" | ||
19 | "io" | ||
20 | "net" | ||
21 | "net/http" | ||
22 | "time" | ||
23 | ) | ||
24 | |||
25 | // Retry invokes the given function, retrying it multiple times if the connection failed or | ||
26 | // the HTTP status response indicates the request should be attempted again. ctx may be nil. | ||
27 | func Retry(ctx context.Context, f func() (*http.Response, error), backoff BackoffStrategy) (*http.Response, error) { | ||
28 | for { | ||
29 | resp, err := f() | ||
30 | |||
31 | var status int | ||
32 | if resp != nil { | ||
33 | status = resp.StatusCode | ||
34 | } | ||
35 | |||
36 | // Return if we shouldn't retry. | ||
37 | pause, retry := backoff.Pause() | ||
38 | if !shouldRetry(status, err) || !retry { | ||
39 | return resp, err | ||
40 | } | ||
41 | |||
42 | // Ensure the response body is closed, if any. | ||
43 | if resp != nil && resp.Body != nil { | ||
44 | resp.Body.Close() | ||
45 | } | ||
46 | |||
47 | // Pause, but still listen to ctx.Done if context is not nil. | ||
48 | var done <-chan struct{} | ||
49 | if ctx != nil { | ||
50 | done = ctx.Done() | ||
51 | } | ||
52 | select { | ||
53 | case <-done: | ||
54 | return nil, ctx.Err() | ||
55 | case <-time.After(pause): | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | // DefaultBackoffStrategy returns a default strategy to use for retrying failed upload requests. | ||
61 | func DefaultBackoffStrategy() BackoffStrategy { | ||
62 | return &ExponentialBackoff{ | ||
63 | Base: 250 * time.Millisecond, | ||
64 | Max: 16 * time.Second, | ||
65 | } | ||
66 | } | ||
67 | |||
68 | // shouldRetry returns true if the HTTP response / error indicates that the | ||
69 | // request should be attempted again. | ||
70 | func shouldRetry(status int, err error) bool { | ||
71 | if 500 <= status && status <= 599 { | ||
72 | return true | ||
73 | } | ||
74 | if status == statusTooManyRequests { | ||
75 | return true | ||
76 | } | ||
77 | if err == io.ErrUnexpectedEOF { | ||
78 | return true | ||
79 | } | ||
80 | if err, ok := err.(net.Error); ok { | ||
81 | return err.Temporary() | ||
82 | } | ||
83 | return false | ||
84 | } | ||