retryer.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package aws
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. )
  7. // RetryMode provides the mode the API client will use to create a retryer
  8. // based on.
  9. type RetryMode string
  10. const (
  11. // RetryModeStandard model provides rate limited retry attempts with
  12. // exponential backoff delay.
  13. RetryModeStandard RetryMode = "standard"
  14. // RetryModeAdaptive model provides attempt send rate limiting on throttle
  15. // responses in addition to standard mode's retry rate limiting.
  16. //
  17. // Adaptive retry mode is experimental and is subject to change in the
  18. // future.
  19. RetryModeAdaptive RetryMode = "adaptive"
  20. )
  21. // ParseRetryMode attempts to parse a RetryMode from the given string.
  22. // Returning error if the value is not a known RetryMode.
  23. func ParseRetryMode(v string) (mode RetryMode, err error) {
  24. switch v {
  25. case "standard":
  26. return RetryModeStandard, nil
  27. case "adaptive":
  28. return RetryModeAdaptive, nil
  29. default:
  30. return mode, fmt.Errorf("unknown RetryMode, %v", v)
  31. }
  32. }
  33. func (m RetryMode) String() string { return string(m) }
  34. // Retryer is an interface to determine if a given error from a
  35. // attempt should be retried, and if so what backoff delay to apply. The
  36. // default implementation used by most services is the retry package's Standard
  37. // type. Which contains basic retry logic using exponential backoff.
  38. type Retryer interface {
  39. // IsErrorRetryable returns if the failed attempt is retryable. This check
  40. // should determine if the error can be retried, or if the error is
  41. // terminal.
  42. IsErrorRetryable(error) bool
  43. // MaxAttempts returns the maximum number of attempts that can be made for
  44. // a attempt before failing. A value of 0 implies that the attempt should
  45. // be retried until it succeeds if the errors are retryable.
  46. MaxAttempts() int
  47. // RetryDelay returns the delay that should be used before retrying the
  48. // attempt. Will return error if the if the delay could not be determined.
  49. RetryDelay(attempt int, opErr error) (time.Duration, error)
  50. // GetRetryToken attempts to deduct the retry cost from the retry token pool.
  51. // Returning the token release function, or error.
  52. GetRetryToken(ctx context.Context, opErr error) (releaseToken func(error) error, err error)
  53. // GetInitialToken returns the initial attempt token that can increment the
  54. // retry token pool if the attempt is successful.
  55. GetInitialToken() (releaseToken func(error) error)
  56. }
  57. // RetryerV2 is an interface to determine if a given error from a attempt
  58. // should be retried, and if so what backoff delay to apply. The default
  59. // implementation used by most services is the retry package's Standard type.
  60. // Which contains basic retry logic using exponential backoff.
  61. //
  62. // RetryerV2 replaces the Retryer interface, deprecating the GetInitialToken
  63. // method in favor of GetAttemptToken which takes a context, and can return an error.
  64. //
  65. // The SDK's retry package's Attempt middleware, and utilities will always
  66. // wrap a Retryer as a RetryerV2. Delegating to GetInitialToken, only if
  67. // GetAttemptToken is not implemented.
  68. type RetryerV2 interface {
  69. Retryer
  70. // GetInitialToken returns the initial attempt token that can increment the
  71. // retry token pool if the attempt is successful.
  72. //
  73. // Deprecated: This method does not provide a way to block using Context,
  74. // nor can it return an error. Use RetryerV2, and GetAttemptToken instead.
  75. GetInitialToken() (releaseToken func(error) error)
  76. // GetAttemptToken returns the send token that can be used to rate limit
  77. // attempt calls. Will be used by the SDK's retry package's Attempt
  78. // middleware to get a send token prior to calling the temp and releasing
  79. // the send token after the attempt has been made.
  80. GetAttemptToken(context.Context) (func(error) error, error)
  81. }
  82. // NopRetryer provides a RequestRetryDecider implementation that will flag
  83. // all attempt errors as not retryable, with a max attempts of 1.
  84. type NopRetryer struct{}
  85. // IsErrorRetryable returns false for all error values.
  86. func (NopRetryer) IsErrorRetryable(error) bool { return false }
  87. // MaxAttempts always returns 1 for the original attempt.
  88. func (NopRetryer) MaxAttempts() int { return 1 }
  89. // RetryDelay is not valid for the NopRetryer. Will always return error.
  90. func (NopRetryer) RetryDelay(int, error) (time.Duration, error) {
  91. return 0, fmt.Errorf("not retrying any attempt errors")
  92. }
  93. // GetRetryToken returns a stub function that does nothing.
  94. func (NopRetryer) GetRetryToken(context.Context, error) (func(error) error, error) {
  95. return nopReleaseToken, nil
  96. }
  97. // GetInitialToken returns a stub function that does nothing.
  98. func (NopRetryer) GetInitialToken() func(error) error {
  99. return nopReleaseToken
  100. }
  101. // GetAttemptToken returns a stub function that does nothing.
  102. func (NopRetryer) GetAttemptToken(context.Context) (func(error) error, error) {
  103. return nopReleaseToken, nil
  104. }
  105. func nopReleaseToken(error) error { return nil }