aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/retry.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/retry.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/retry.go148
1 files changed, 148 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/retry.go b/vendor/github.com/minio/minio-go/v7/retry.go
new file mode 100644
index 0000000..1c6105e
--- /dev/null
+++ b/vendor/github.com/minio/minio-go/v7/retry.go
@@ -0,0 +1,148 @@
1/*
2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2015-2017 MinIO, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package minio
19
20import (
21 "context"
22 "crypto/x509"
23 "errors"
24 "net/http"
25 "net/url"
26 "time"
27)
28
29// MaxRetry is the maximum number of retries before stopping.
30var MaxRetry = 10
31
32// MaxJitter will randomize over the full exponential backoff time
33const MaxJitter = 1.0
34
35// NoJitter disables the use of jitter for randomizing the exponential backoff time
36const NoJitter = 0.0
37
38// DefaultRetryUnit - default unit multiplicative per retry.
39// defaults to 200 * time.Millisecond
40var DefaultRetryUnit = 200 * time.Millisecond
41
42// DefaultRetryCap - Each retry attempt never waits no longer than
43// this maximum time duration.
44var DefaultRetryCap = time.Second
45
46// newRetryTimer creates a timer with exponentially increasing
47// delays until the maximum retry attempts are reached.
48func (c *Client) newRetryTimer(ctx context.Context, maxRetry int, unit, cap time.Duration, jitter float64) <-chan int {
49 attemptCh := make(chan int)
50
51 // computes the exponential backoff duration according to
52 // https://www.awsarchitectureblog.com/2015/03/backoff.html
53 exponentialBackoffWait := func(attempt int) time.Duration {
54 // normalize jitter to the range [0, 1.0]
55 if jitter < NoJitter {
56 jitter = NoJitter
57 }
58 if jitter > MaxJitter {
59 jitter = MaxJitter
60 }
61
62 // sleep = random_between(0, min(cap, base * 2 ** attempt))
63 sleep := unit * time.Duration(1<<uint(attempt))
64 if sleep > cap {
65 sleep = cap
66 }
67 if jitter != NoJitter {
68 sleep -= time.Duration(c.random.Float64() * float64(sleep) * jitter)
69 }
70 return sleep
71 }
72
73 go func() {
74 defer close(attemptCh)
75 for i := 0; i < maxRetry; i++ {
76 select {
77 case attemptCh <- i + 1:
78 case <-ctx.Done():
79 return
80 }
81
82 select {
83 case <-time.After(exponentialBackoffWait(i)):
84 case <-ctx.Done():
85 return
86 }
87 }
88 }()
89 return attemptCh
90}
91
92// List of AWS S3 error codes which are retryable.
93var retryableS3Codes = map[string]struct{}{
94 "RequestError": {},
95 "RequestTimeout": {},
96 "Throttling": {},
97 "ThrottlingException": {},
98 "RequestLimitExceeded": {},
99 "RequestThrottled": {},
100 "InternalError": {},
101 "ExpiredToken": {},
102 "ExpiredTokenException": {},
103 "SlowDown": {},
104 // Add more AWS S3 codes here.
105}
106
107// isS3CodeRetryable - is s3 error code retryable.
108func isS3CodeRetryable(s3Code string) (ok bool) {
109 _, ok = retryableS3Codes[s3Code]
110 return ok
111}
112
113// List of HTTP status codes which are retryable.
114var retryableHTTPStatusCodes = map[int]struct{}{
115 429: {}, // http.StatusTooManyRequests is not part of the Go 1.5 library, yet
116 499: {}, // client closed request, retry. A non-standard status code introduced by nginx.
117 http.StatusInternalServerError: {},
118 http.StatusBadGateway: {},
119 http.StatusServiceUnavailable: {},
120 http.StatusGatewayTimeout: {},
121 // Add more HTTP status codes here.
122}
123
124// isHTTPStatusRetryable - is HTTP error code retryable.
125func isHTTPStatusRetryable(httpStatusCode int) (ok bool) {
126 _, ok = retryableHTTPStatusCodes[httpStatusCode]
127 return ok
128}
129
130// For now, all http Do() requests are retriable except some well defined errors
131func isRequestErrorRetryable(err error) bool {
132 if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
133 return false
134 }
135 if ue, ok := err.(*url.Error); ok {
136 e := ue.Unwrap()
137 switch e.(type) {
138 // x509: certificate signed by unknown authority
139 case x509.UnknownAuthorityError:
140 return false
141 }
142 switch e.Error() {
143 case "http: server gave HTTP response to HTTPS client":
144 return false
145 }
146 }
147 return true
148}