6 "github.com/aws/aws-sdk-go/aws"
7 "github.com/aws/aws-sdk-go/aws/awserr"
10 // Retryer is an interface to control retry logic for a given service.
11 // The default implementation used by most services is the client.DefaultRetryer
12 // structure, which contains basic retry logic using exponential backoff.
13 type Retryer interface {
14 RetryRules(*Request) time.Duration
15 ShouldRetry(*Request) bool
19 // WithRetryer sets a config Retryer value to the given Config returning it
21 func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
26 // retryableCodes is a collection of service response codes which are retry-able
27 // without any further action.
28 var retryableCodes = map[string]struct{}{
31 ErrCodeResponseTimeout: {},
32 "RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
35 var throttleCodes = map[string]struct{}{
36 "ProvisionedThroughputExceededException": {},
38 "ThrottlingException": {},
39 "RequestLimitExceeded": {},
40 "RequestThrottled": {},
41 "RequestThrottledException": {},
42 "TooManyRequestsException": {}, // Lambda functions
43 "PriorRequestNotComplete": {}, // Route53
44 "TransactionInProgressException": {},
47 // credsExpiredCodes is a collection of error codes which signify the credentials
48 // need to be refreshed. Expired tokens require refreshing of credentials, and
49 // resigning before the request can be retried.
50 var credsExpiredCodes = map[string]struct{}{
52 "ExpiredTokenException": {},
53 "RequestExpired": {}, // EC2 Only
56 func isCodeThrottle(code string) bool {
57 _, ok := throttleCodes[code]
61 func isCodeRetryable(code string) bool {
62 if _, ok := retryableCodes[code]; ok {
66 return isCodeExpiredCreds(code)
69 func isCodeExpiredCreds(code string) bool {
70 _, ok := credsExpiredCodes[code]
74 var validParentCodes = map[string]struct{}{
75 ErrCodeSerialization: {},
79 type temporaryError interface {
83 func isNestedErrorRetryable(parentErr awserr.Error) bool {
88 if _, ok := validParentCodes[parentErr.Code()]; !ok {
92 err := parentErr.OrigErr()
97 if aerr, ok := err.(awserr.Error); ok {
98 return isCodeRetryable(aerr.Code())
101 if t, ok := err.(temporaryError); ok {
102 return t.Temporary() || isErrConnectionReset(err)
105 return isErrConnectionReset(err)
108 // IsErrorRetryable returns whether the error is retryable, based on its Code.
109 // Returns false if error is nil.
110 func IsErrorRetryable(err error) bool {
112 if aerr, ok := err.(awserr.Error); ok {
113 return isCodeRetryable(aerr.Code()) || isNestedErrorRetryable(aerr)
119 // IsErrorThrottle returns whether the error is to be throttled based on its code.
120 // Returns false if error is nil.
121 func IsErrorThrottle(err error) bool {
123 if aerr, ok := err.(awserr.Error); ok {
124 return isCodeThrottle(aerr.Code())
130 // IsErrorExpiredCreds returns whether the error code is a credential expiry error.
131 // Returns false if error is nil.
132 func IsErrorExpiredCreds(err error) bool {
134 if aerr, ok := err.(awserr.Error); ok {
135 return isCodeExpiredCreds(aerr.Code())
141 // IsErrorRetryable returns whether the error is retryable, based on its Code.
142 // Returns false if the request has no Error set.
144 // Alias for the utility function IsErrorRetryable
145 func (r *Request) IsErrorRetryable() bool {
146 return IsErrorRetryable(r.Error)
149 // IsErrorThrottle returns whether the error is to be throttled based on its code.
150 // Returns false if the request has no Error set
152 // Alias for the utility function IsErrorThrottle
153 func (r *Request) IsErrorThrottle() bool {
154 return IsErrorThrottle(r.Error)
157 // IsErrorExpired returns whether the error code is a credential expiry error.
158 // Returns false if the request has no Error set.
160 // Alias for the utility function IsErrorExpiredCreds
161 func (r *Request) IsErrorExpired() bool {
162 return IsErrorExpiredCreds(r.Error)