retryer.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package request
  2. import (
  3. "net"
  4. "os"
  5. "syscall"
  6. "time"
  7. "github.com/aws/aws-sdk-go/aws"
  8. "github.com/aws/aws-sdk-go/aws/awserr"
  9. )
  10. // Retryer is an interface to control retry logic for a given service.
  11. // The default implementation used by most services is the service.DefaultRetryer
  12. // structure, which contains basic retry logic using exponential backoff.
  13. type Retryer interface {
  14. RetryRules(*Request) time.Duration
  15. ShouldRetry(*Request) bool
  16. MaxRetries() int
  17. }
  18. // WithRetryer sets a config Retryer value to the given Config returning it
  19. // for chaining.
  20. func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
  21. cfg.Retryer = retryer
  22. return cfg
  23. }
  24. // retryableCodes is a collection of service response codes which are retry-able
  25. // without any further action.
  26. var retryableCodes = map[string]struct{}{
  27. "RequestError": {},
  28. "RequestTimeout": {},
  29. ErrCodeResponseTimeout: {},
  30. "RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
  31. }
  32. var throttleCodes = map[string]struct{}{
  33. "ProvisionedThroughputExceededException": {},
  34. "Throttling": {},
  35. "ThrottlingException": {},
  36. "RequestLimitExceeded": {},
  37. "RequestThrottled": {},
  38. "LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once
  39. "TooManyRequestsException": {}, // Lambda functions
  40. "PriorRequestNotComplete": {}, // Route53
  41. }
  42. // credsExpiredCodes is a collection of error codes which signify the credentials
  43. // need to be refreshed. Expired tokens require refreshing of credentials, and
  44. // resigning before the request can be retried.
  45. var credsExpiredCodes = map[string]struct{}{
  46. "ExpiredToken": {},
  47. "ExpiredTokenException": {},
  48. "RequestExpired": {}, // EC2 Only
  49. }
  50. func isCodeThrottle(code string) bool {
  51. _, ok := throttleCodes[code]
  52. return ok
  53. }
  54. func isCodeRetryable(code string) bool {
  55. if _, ok := retryableCodes[code]; ok {
  56. return true
  57. }
  58. return isCodeExpiredCreds(code)
  59. }
  60. func isCodeExpiredCreds(code string) bool {
  61. _, ok := credsExpiredCodes[code]
  62. return ok
  63. }
  64. func isSerializationErrorRetryable(err error) bool {
  65. if err == nil {
  66. return false
  67. }
  68. if aerr, ok := err.(awserr.Error); ok {
  69. return isCodeRetryable(aerr.Code())
  70. }
  71. if opErr, ok := err.(*net.OpError); ok {
  72. if sysErr, ok := opErr.Err.(*os.SyscallError); ok {
  73. return sysErr.Err == syscall.ECONNRESET
  74. }
  75. }
  76. return false
  77. }
  78. // IsErrorRetryable returns whether the error is retryable, based on its Code.
  79. // Returns false if the request has no Error set.
  80. func (r *Request) IsErrorRetryable() bool {
  81. if r.Error != nil {
  82. if err, ok := r.Error.(awserr.Error); ok && err.Code() != ErrCodeSerialization {
  83. return isCodeRetryable(err.Code())
  84. } else if ok {
  85. return isSerializationErrorRetryable(err.OrigErr())
  86. }
  87. }
  88. return false
  89. }
  90. // IsErrorThrottle returns whether the error is to be throttled based on its code.
  91. // Returns false if the request has no Error set
  92. func (r *Request) IsErrorThrottle() bool {
  93. if r.Error != nil {
  94. if err, ok := r.Error.(awserr.Error); ok {
  95. return isCodeThrottle(err.Code())
  96. }
  97. }
  98. return false
  99. }
  100. // IsErrorExpired returns whether the error code is a credential expiry error.
  101. // Returns false if the request has no Error set.
  102. func (r *Request) IsErrorExpired() bool {
  103. if r.Error != nil {
  104. if err, ok := r.Error.(awserr.Error); ok {
  105. return isCodeExpiredCreds(err.Code())
  106. }
  107. }
  108. return false
  109. }