]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / client / default_retryer.go
1 package client
2
3 import (
4 "strconv"
5 "time"
6
7 "github.com/aws/aws-sdk-go/aws/request"
8 "github.com/aws/aws-sdk-go/internal/sdkrand"
9 )
10
11 // DefaultRetryer implements basic retry logic using exponential backoff for
12 // most services. If you want to implement custom retry logic, implement the
13 // request.Retryer interface or create a structure type that composes this
14 // struct and override the specific methods. For example, to override only
15 // the MaxRetries method:
16 //
17 // type retryer struct {
18 // client.DefaultRetryer
19 // }
20 //
21 // // This implementation always has 100 max retries
22 // func (d retryer) MaxRetries() int { return 100 }
23 type DefaultRetryer struct {
24 NumMaxRetries int
25 }
26
27 // MaxRetries returns the number of maximum returns the service will use to make
28 // an individual API request.
29 func (d DefaultRetryer) MaxRetries() int {
30 return d.NumMaxRetries
31 }
32
33 // RetryRules returns the delay duration before retrying this request again
34 func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
35 // Set the upper limit of delay in retrying at ~five minutes
36 minTime := 30
37 throttle := d.shouldThrottle(r)
38 if throttle {
39 if delay, ok := getRetryDelay(r); ok {
40 return delay
41 }
42
43 minTime = 500
44 }
45
46 retryCount := r.RetryCount
47 if throttle && retryCount > 8 {
48 retryCount = 8
49 } else if retryCount > 13 {
50 retryCount = 13
51 }
52
53 delay := (1 << uint(retryCount)) * (sdkrand.SeededRand.Intn(minTime) + minTime)
54 return time.Duration(delay) * time.Millisecond
55 }
56
57 // ShouldRetry returns true if the request should be retried.
58 func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
59 // If one of the other handlers already set the retry state
60 // we don't want to override it based on the service's state
61 if r.Retryable != nil {
62 return *r.Retryable
63 }
64
65 if r.HTTPResponse.StatusCode >= 500 && r.HTTPResponse.StatusCode != 501 {
66 return true
67 }
68 return r.IsErrorRetryable() || d.shouldThrottle(r)
69 }
70
71 // ShouldThrottle returns true if the request should be throttled.
72 func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
73 switch r.HTTPResponse.StatusCode {
74 case 429:
75 case 502:
76 case 503:
77 case 504:
78 default:
79 return r.IsErrorThrottle()
80 }
81
82 return true
83 }
84
85 // This will look in the Retry-After header, RFC 7231, for how long
86 // it will wait before attempting another request
87 func getRetryDelay(r *request.Request) (time.Duration, bool) {
88 if !canUseRetryAfterHeader(r) {
89 return 0, false
90 }
91
92 delayStr := r.HTTPResponse.Header.Get("Retry-After")
93 if len(delayStr) == 0 {
94 return 0, false
95 }
96
97 delay, err := strconv.Atoi(delayStr)
98 if err != nil {
99 return 0, false
100 }
101
102 return time.Duration(delay) * time.Second, true
103 }
104
105 // Will look at the status code to see if the retry header pertains to
106 // the status code.
107 func canUseRetryAfterHeader(r *request.Request) bool {
108 switch r.HTTPResponse.StatusCode {
109 case 429:
110 case 503:
111 default:
112 return false
113 }
114
115 return true
116 }