| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- package request
- import (
- "time"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/awserr"
- )
- // Retryer is an interface to control retry logic for a given service.
- // The default implementation used by most services is the client.DefaultRetryer
- // structure, which contains basic retry logic using exponential backoff.
- type Retryer interface {
- RetryRules(*Request) time.Duration
- ShouldRetry(*Request) bool
- MaxRetries() int
- }
- // WithRetryer sets a config Retryer value to the given Config returning it
- // for chaining.
- func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
- cfg.Retryer = retryer
- return cfg
- }
- // retryableCodes is a collection of service response codes which are retry-able
- // without any further action.
- var retryableCodes = map[string]struct{}{
- "RequestError": {},
- "RequestTimeout": {},
- ErrCodeResponseTimeout: {},
- "RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
- }
- var throttleCodes = map[string]struct{}{
- "ProvisionedThroughputExceededException": {},
- "Throttling": {},
- "ThrottlingException": {},
- "RequestLimitExceeded": {},
- "RequestThrottled": {},
- "TooManyRequestsException": {}, // Lambda functions
- "PriorRequestNotComplete": {}, // Route53
- }
- // credsExpiredCodes is a collection of error codes which signify the credentials
- // need to be refreshed. Expired tokens require refreshing of credentials, and
- // resigning before the request can be retried.
- var credsExpiredCodes = map[string]struct{}{
- "ExpiredToken": {},
- "ExpiredTokenException": {},
- "RequestExpired": {}, // EC2 Only
- }
- func isCodeThrottle(code string) bool {
- _, ok := throttleCodes[code]
- return ok
- }
- func isCodeRetryable(code string) bool {
- if _, ok := retryableCodes[code]; ok {
- return true
- }
- return isCodeExpiredCreds(code)
- }
- func isCodeExpiredCreds(code string) bool {
- _, ok := credsExpiredCodes[code]
- return ok
- }
- var validParentCodes = map[string]struct{}{
- ErrCodeSerialization: {},
- ErrCodeRead: {},
- }
- type temporaryError interface {
- Temporary() bool
- }
- func isNestedErrorRetryable(parentErr awserr.Error) bool {
- if parentErr == nil {
- return false
- }
- if _, ok := validParentCodes[parentErr.Code()]; !ok {
- return false
- }
- err := parentErr.OrigErr()
- if err == nil {
- return false
- }
- if aerr, ok := err.(awserr.Error); ok {
- return isCodeRetryable(aerr.Code())
- }
- if t, ok := err.(temporaryError); ok {
- return t.Temporary()
- }
- return isErrConnectionReset(err)
- }
- // IsErrorRetryable returns whether the error is retryable, based on its Code.
- // Returns false if error is nil.
- func IsErrorRetryable(err error) bool {
- if err != nil {
- if aerr, ok := err.(awserr.Error); ok {
- return isCodeRetryable(aerr.Code()) || isNestedErrorRetryable(aerr)
- }
- }
- return false
- }
- // IsErrorThrottle returns whether the error is to be throttled based on its code.
- // Returns false if error is nil.
- func IsErrorThrottle(err error) bool {
- if err != nil {
- if aerr, ok := err.(awserr.Error); ok {
- return isCodeThrottle(aerr.Code())
- }
- }
- return false
- }
- // IsErrorExpiredCreds returns whether the error code is a credential expiry error.
- // Returns false if error is nil.
- func IsErrorExpiredCreds(err error) bool {
- if err != nil {
- if aerr, ok := err.(awserr.Error); ok {
- return isCodeExpiredCreds(aerr.Code())
- }
- }
- return false
- }
- // IsErrorRetryable returns whether the error is retryable, based on its Code.
- // Returns false if the request has no Error set.
- //
- // Alias for the utility function IsErrorRetryable
- func (r *Request) IsErrorRetryable() bool {
- return IsErrorRetryable(r.Error)
- }
- // IsErrorThrottle returns whether the error is to be throttled based on its code.
- // Returns false if the request has no Error set
- //
- // Alias for the utility function IsErrorThrottle
- func (r *Request) IsErrorThrottle() bool {
- return IsErrorThrottle(r.Error)
- }
- // IsErrorExpired returns whether the error code is a credential expiry error.
- // Returns false if the request has no Error set.
- //
- // Alias for the utility function IsErrorExpiredCreds
- func (r *Request) IsErrorExpired() bool {
- return IsErrorExpiredCreds(r.Error)
- }
|