diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 40c2441ab99..f4c96bff979 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,6 +1,16 @@ Breaking Change --- +* Update SDK retry behavior + * Significant updates were made the SDK's retry behavior. The SDK will now retry all connections error. In addition, to changing what errors are retried the SDK's retry behavior not distinguish the difference between throttling errors, and regular retryable errors. All errors will be retried with the same backoff jitter delay scaling. + * The SDK will attempt an operation request 3 times by default. This is one less than the previous initial request with 3 retires. + * New helper functions in the new `aws/retry` package allow wrapping a `Retrier` with custom behavior, overriding the base `Retrier`, (e.g. `AddWithErrorCodes`, and `AddWithMaxAttempts`) +* Update SDK error handling + * Updates the SDK's handling of errors to take advantage of Go 1.13's new `errors.As`, `Is`, and `Unwrap`. The SDK's errors were updated to satisfy the `Unwrap` interface, returning the underlying error. + * With this update, you can now more easily access the SDK's layered errors, and meaningful state such as, `Timeout`, `Temporary`, and other states added to the SDK such as `CanceledError`. +* Bump SDK minimum supported version from Go 1.12 to Go 1.13 + * The SDK's minimum supported version is bumped to take advantage of Go 1.13's updated `errors` package. + Services --- @@ -14,6 +24,10 @@ SDK Features * Fixes [#338](https://github.com/aws/aws-sdk-go-v2/issues/338) * Adds Support for `credential_source` * Fixes [#274](https://github.com/aws/aws-sdk-go-v2/issues/274) +* `aws/awserr`: Adds support for Go 1.13's `errors.Unwrap` ([#487](https://github.com/aws/aws-sdk-go-v2/pull/487)) +* `aws`: Updates SDK retry behavior ([#487](https://github.com/aws/aws-sdk-go-v2/pull/487)) + * `aws/retry`: New package defining logic to determine if a request should be retried, and backoff. + * `aws/ratelimit`: New package defining rate limit logic such as token bucket used by the `retry.Standard` retrier. SDK Enhancements --- diff --git a/README.md b/README.md index d2e2ac44c8a..3beddb91dc9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ `aws-sdk-go-v2` is the **Developer Preview** (aka **beta**) for the v2 AWS SDK for the Go programming language. This Developer Preview is provided to receive feedback from the language community on SDK changes prior to the final release. As such users should expect the SDK to release minor version releases that break backwards compatability. The release notes for the breaking change will include information about the breaking change, and how you can migrate to the latest version. -Check out the [Issues] and [Projects] for design and updates being made to the SDK. The v2 SDK requires a minimum version of `Go 1.12`. +Check out the [Issues] and [Projects] for design and updates being made to the SDK. The v2 SDK requires a minimum version of `Go 1.13`. We'll be expanding out the [Issues] and [Projects] sections with additional changes to the SDK based on your feedback, and SDK's core's improvements. Check the the SDK's [CHANGE_LOG] for information about the latest updates to the SDK. diff --git a/aws/awserr/error.go b/aws/awserr/error.go index 56fdfc2bfc7..70aee01a295 100644 --- a/aws/awserr/error.go +++ b/aws/awserr/error.go @@ -16,15 +16,16 @@ package awserr // // Get error details // log.Println("Error:", awsErr.Code(), awsErr.Message()) // -// // Prints out full error message, including original error if there was one. -// log.Println("Error:", awsErr.Error()) +// // Prints out full error message, including original error if +// // there was one. +// log.Println("Error:", awsErr) // // // Get original error -// if origErr := awsErr.OrigErr(); origErr != nil { +// if origErr := errors.Unwrap(awsErr); origErr != nil { // // operate on original error. // } // } else { -// fmt.Println(err.Error()) +// fmt.Println(err) // } // } // @@ -37,60 +38,31 @@ type Error interface { // Returns the error details message. Message() string - - // Returns the original error if one was set. Nil is returned if not set. - OrigErr() error -} - -// BatchError is a batch of errors which also wraps lower level errors with -// code, message, and original errors. Calling Error() will include all errors -// that occurred in the batch. -// -// Deprecated: Replaced with BatchedErrors. Only defined for backwards -// compatibility. -type BatchError interface { - // Satisfy the generic error interface. - error - - // Returns the short phrase depicting the classification of the error. - Code() string - - // Returns the error details message. - Message() string - - // Returns the original error if one was set. Nil is returned if not set. - OrigErrs() []error } // BatchedErrors is a batch of errors which also wraps lower level errors with // code, message, and original errors. Calling Error() will include all errors // that occurred in the batch. -// -// Replaces BatchError type BatchedErrors interface { // Satisfy the base Error interface. Error // Returns the original error if one was set. Nil is returned if not set. - OrigErrs() []error + Errs() []error } // New returns an Error object described by the code, message, and origErr. // // If origErr satisfies the Error interface it will not be wrapped within a new // Error object and will instead be returned. -func New(code, message string, origErr error) Error { - var errs []error - if origErr != nil { - errs = append(errs, origErr) - } - return newBaseError(code, message, errs) +func New(code, message string, err error) Error { + return newBaseError(code, message, err) } // NewBatchError returns an BatchedErrors with a collection of errors as an // array of errors. func NewBatchError(code, message string, errs []error) BatchedErrors { - return newBaseError(code, message, errs) + return newBatchError(code, message, errs) } // A RequestFailure is an interface to extract request failure information from diff --git a/aws/awserr/types.go b/aws/awserr/types.go index 0202a008f5d..fcf6ce90367 100644 --- a/aws/awserr/types.go +++ b/aws/awserr/types.go @@ -1,6 +1,9 @@ package awserr -import "fmt" +import ( + "errors" + "fmt" +) // SprintError returns a string of the formatted error code. // @@ -12,7 +15,7 @@ func SprintError(code, message, extra string, origErr error) string { msg = fmt.Sprintf("%s\n\t%s", msg, extra) } if origErr != nil { - msg = fmt.Sprintf("%s\ncaused by: %s", msg, origErr.Error()) + msg = fmt.Sprintf("%s\ncaused by: %v", msg, origErr) } return msg } @@ -31,7 +34,7 @@ type baseError struct { // Optional original error this error is based off of. Allows building // chained errors. - errs []error + err error } // newBaseError returns an error object for the code, message, and errors. @@ -44,11 +47,11 @@ type baseError struct { // // origErrs is the error objects which will be nested under the new errors to // be returned. -func newBaseError(code, message string, origErrs []error) *baseError { +func newBaseError(code, message string, err error) *baseError { b := &baseError{ code: code, message: message, - errs: origErrs, + err: err, } return b @@ -60,12 +63,7 @@ func newBaseError(code, message string, origErrs []error) *baseError { // // Satisfies the error interface. func (b baseError) Error() string { - size := len(b.errs) - if size > 0 { - return SprintError(b.code, b.message, "", errorList(b.errs)) - } - - return SprintError(b.code, b.message, "", nil) + return SprintError(b.code, b.message, "", b.err) } // String returns the string representation of the error. @@ -84,27 +82,37 @@ func (b baseError) Message() string { return b.message } -// OrigErr returns the original error if one was set. Nil is returned if no +// Unwrap returns the original error if one was set. Nil is returned if no // error was set. This only returns the first element in the list. If the full // list is needed, use BatchedErrors. -func (b baseError) OrigErr() error { - switch len(b.errs) { - case 0: - return nil - case 1: - return b.errs[0] - default: - if err, ok := b.errs[0].(Error); ok { - return NewBatchError(err.Code(), err.Message(), b.errs[1:]) - } - return NewBatchError("BatchedErrors", - "multiple errors occurred", b.errs) +func (b baseError) Unwrap() error { + return b.err +} + +type batchError struct { + *baseError + errs []error +} + +func newBatchError(code, message string, errs []error) *batchError { + return &batchError{ + baseError: newBaseError(code, message, nil), + errs: errs, + } +} + +func (b batchError) Error() string { + size := len(b.errs) + if size > 0 { + return SprintError(b.code, b.message, "", errorList(b.errs)) } + + return SprintError(b.code, b.message, "", nil) } -// OrigErrs returns the original errors if one was set. An empty slice is -// returned if no error was set. -func (b baseError) OrigErrs() []error { +// Errs returns the original errors if one was set. Nil is returned if no error +// was set. +func (b batchError) Errs() []error { return b.errs } @@ -142,13 +150,11 @@ func newRequestError(err Error, statusCode int, requestID string) *requestError func (r requestError) Error() string { extra := fmt.Sprintf("status code: %d, request id: %s", r.statusCode, r.requestID) - return SprintError(r.Code(), r.Message(), extra, r.OrigErr()) + return SprintError(r.Code(), r.Message(), extra, r.Unwrap()) } -// String returns the string representation of the error. -// Alias for Error to satisfy the stringer interface. -func (r requestError) String() string { - return r.Error() +func (r requestError) Unwrap() error { + return errors.Unwrap(r.awsError) } // StatusCode returns the wrapped status code for the error @@ -161,13 +167,14 @@ func (r requestError) RequestID() string { return r.requestID } -// OrigErrs returns the original errors if one was set. An empty slice is -// returned if no error was set. -func (r requestError) OrigErrs() []error { +// Errs returns the original errors if one was set. Nil is returned if no error +// is set. +func (r requestError) Errs() []error { if b, ok := r.awsError.(BatchedErrors); ok { - return b.OrigErrs() + return b.Errs() } - return []error{r.OrigErr()} + + return nil } // An error list that satisfies the golang interface diff --git a/aws/client.go b/aws/client.go index 38cde6db17e..e8d13bd2155 100644 --- a/aws/client.go +++ b/aws/client.go @@ -53,11 +53,6 @@ func NewClient(cfg Config, metadata Metadata) *Client { svc.Config.HTTPClient = wrapWithoutRedirect(c) } - retryer := cfg.Retryer - if retryer == nil { - retryer = NewDefaultRetryer() - } - svc.Retryer = retryer svc.AddDebugHandlers() return svc } diff --git a/aws/config.go b/aws/config.go index 00c7781e7ae..014089fcd5a 100644 --- a/aws/config.go +++ b/aws/config.go @@ -32,18 +32,8 @@ type Config struct { Handlers Handlers // Retryer guides how HTTP requests should be retried in case of - // recoverable failures. - // - // When nil or the value does not implement the request.Retryer interface, - // the client.DefaultRetryer will be used. - // - // When both Retryer and MaxRetries are non-nil, the former is used and - // the latter ignored. - // - // To set the Retryer field in a type-safe manner and with chaining, use - // the request.WithRetryer helper function: - // - // cfg := request.WithRetryer(aws.NewConfig(), myRetryer) + // recoverable failures. When nil the API client will use a default + // retryer. Retryer Retryer // An integer value representing the logging level. The default log level diff --git a/aws/connection_reset_error.go b/aws/connection_reset_error.go deleted file mode 100644 index 5fe8be630a9..00000000000 --- a/aws/connection_reset_error.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build !appengine,!plan9 - -package aws - -import ( - "net" - "os" - "syscall" -) - -func isErrConnectionReset(err error) bool { - if opErr, ok := err.(*net.OpError); ok { - if sysErr, ok := opErr.Err.(*os.SyscallError); ok { - return sysErr.Err == syscall.ECONNRESET - } - } - - return false -} diff --git a/aws/connection_reset_error_other.go b/aws/connection_reset_error_other.go deleted file mode 100644 index ca8422eff28..00000000000 --- a/aws/connection_reset_error_other.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build appengine plan9 - -package aws - -import ( - "strings" -) - -func isErrConnectionReset(err error) bool { - return strings.Contains(err.Error(), "connection reset") -} diff --git a/aws/connection_reset_error_other_test.go b/aws/connection_reset_error_other_test.go deleted file mode 100644 index c6984d32725..00000000000 --- a/aws/connection_reset_error_other_test.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build appengine plan9 - -package aws_test - -import ( - "errors" -) - -var stubConnectionResetError = errors.New("connection reset") diff --git a/aws/connection_reset_error_test.go b/aws/connection_reset_error_test.go deleted file mode 100644 index 01dcd75250f..00000000000 --- a/aws/connection_reset_error_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !appengine,!plan9 - -package aws_test - -import ( - "net" - "os" - "syscall" -) - -var stubConnectionResetError = &net.OpError{Err: &os.SyscallError{Syscall: "read", Err: syscall.ECONNRESET}} diff --git a/aws/context.go b/aws/context.go deleted file mode 100644 index 399d9ac50af..00000000000 --- a/aws/context.go +++ /dev/null @@ -1,25 +0,0 @@ -package aws - -import ( - "context" - "time" -) - -// SleepWithContext will wait for the timer duration to expire, or the context -// is canceled. Which ever happens first. If the context is canceled the Context's -// error will be returned. -// -// Expects Context to always return a non-nil error if the Done channel is closed. -func SleepWithContext(ctx context.Context, dur time.Duration) error { - t := time.NewTimer(dur) - defer t.Stop() - - select { - case <-t.C: - break - case <-ctx.Done(): - return ctx.Err() - } - - return nil -} diff --git a/aws/context_test.go b/aws/context_test.go deleted file mode 100644 index 57ad8612fb1..00000000000 --- a/aws/context_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package aws_test - -import ( - "fmt" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/internal/awstesting" -) - -func TestSleepWithContext(t *testing.T) { - ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} - - err := aws.SleepWithContext(ctx, 1*time.Millisecond) - if err != nil { - t.Errorf("expect context to not be canceled, got %v", err) - } -} - -func TestSleepWithContext_Canceled(t *testing.T) { - ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} - - expectErr := fmt.Errorf("context canceled") - - ctx.Error = expectErr - close(ctx.DoneCh) - - err := aws.SleepWithContext(ctx, 1*time.Millisecond) - if err == nil { - t.Fatalf("expect error, did not get one") - } - - if e, a := expectErr, err; e != a { - t.Errorf("expect %v error, got %v", e, a) - } -} diff --git a/aws/default_retryer.go b/aws/default_retryer.go deleted file mode 100644 index 88b6d21d9d5..00000000000 --- a/aws/default_retryer.go +++ /dev/null @@ -1,165 +0,0 @@ -package aws - -import ( - "math" - "math/rand" - "strconv" - "sync" - "time" -) - -// DefaultRetryer implements basic retry logic using exponential backoff for -// most services. You can implement your own custom retryer by implementing -// retryer interface. -type DefaultRetryer struct { - NumMaxRetries int - MinRetryDelay time.Duration - MinThrottleDelay time.Duration - MaxRetryDelay time.Duration - MaxThrottleDelay time.Duration -} - -const ( - // DefaultRetryerMaxNumRetries sets maximum number of retries - DefaultRetryerMaxNumRetries = 3 - - // DefaultRetryerMinRetryDelay sets minimum retry delay - DefaultRetryerMinRetryDelay = 30 * time.Millisecond - - // DefaultRetryerMinThrottleDelay sets minimum delay when throttled - DefaultRetryerMinThrottleDelay = 500 * time.Millisecond - - // DefaultRetryerMaxRetryDelay sets maximum retry delay - DefaultRetryerMaxRetryDelay = 300 * time.Second - - // DefaultRetryerMaxThrottleDelay sets maximum delay when throttled - DefaultRetryerMaxThrottleDelay = 300 * time.Second -) - -// MaxRetries returns the number of maximum returns the service will use to make -// an individual API -func (d DefaultRetryer) MaxRetries() int { - return d.NumMaxRetries -} - -var seededRand = rand.New(&lockedSource{src: rand.NewSource(time.Now().UnixNano())}) - -// NewDefaultRetryer returns a retryer initialized with default values and optionally takes function -// to override values for default retryer. -func NewDefaultRetryer(opts ...func(d *DefaultRetryer)) DefaultRetryer { - d := DefaultRetryer{ - NumMaxRetries: DefaultRetryerMaxNumRetries, - MinRetryDelay: DefaultRetryerMinRetryDelay, - MinThrottleDelay: DefaultRetryerMinThrottleDelay, - MaxRetryDelay: DefaultRetryerMaxRetryDelay, - MaxThrottleDelay: DefaultRetryerMaxThrottleDelay, - } - - for _, opt := range opts { - opt(&d) - } - return d -} - -// RetryRules returns the delay duration before retrying this request again -// -// Note: RetryRules method must be a value receiver so that the -// defaultRetryer is safe. -func (d DefaultRetryer) RetryRules(r *Request) time.Duration { - - minDelay := d.MinRetryDelay - maxDelay := d.MaxRetryDelay - - var initialDelay time.Duration - isThrottle := r.IsErrorThrottle() - if isThrottle { - if delay, ok := getRetryAfterDelay(r); ok { - initialDelay = delay - } - minDelay = d.MinThrottleDelay - maxDelay = d.MaxThrottleDelay - } - - retryCount := r.RetryCount - var delay time.Duration - - // Logic to cap the retry count based on the minDelay provided - actualRetryCount := int(math.Log2(float64(minDelay))) + 1 - if actualRetryCount < 63-retryCount { - delay = time.Duration(1< maxDelay { - delay = getJitterDelay(maxDelay / 2) - } - } else { - delay = getJitterDelay(maxDelay / 2) - } - return delay + initialDelay -} - -// getJitterDelay returns a jittered delay for retry -func getJitterDelay(duration time.Duration) time.Duration { - return time.Duration(seededRand.Int63n(int64(duration)) + int64(duration)) -} - -// ShouldRetry returns true if the request should be retried. -func (d DefaultRetryer) ShouldRetry(r *Request) bool { - // If one of the other handlers already set the retry state - // we don't want to override it based on the service's state - if r.Retryable != nil { - return *r.Retryable - } - - return r.IsErrorRetryable() || r.IsErrorThrottle() -} - -// This will look in the Retry-After header, RFC 7231, for how long -// it will wait before attempting another request -func getRetryAfterDelay(r *Request) (time.Duration, bool) { - if !canUseRetryAfterHeader(r) { - return 0, false - } - - delayStr := r.HTTPResponse.Header.Get("Retry-After") - if len(delayStr) == 0 { - return 0, false - } - - delay, err := strconv.Atoi(delayStr) - if err != nil { - return 0, false - } - - return time.Duration(delay) * time.Second, true -} - -// Will look at the status code to see if the retry header pertains to -// the status code. -func canUseRetryAfterHeader(r *Request) bool { - switch r.HTTPResponse.StatusCode { - case 429: - case 503: - default: - return false - } - - return true -} - -// lockedSource is a thread-safe implementation of rand.Source -type lockedSource struct { - lk sync.Mutex - src rand.Source -} - -func (r *lockedSource) Int63() (n int64) { - r.lk.Lock() - n = r.src.Int63() - r.lk.Unlock() - return -} - -func (r *lockedSource) Seed(seed int64) { - r.lk.Lock() - r.src.Seed(seed) - r.lk.Unlock() -} diff --git a/aws/default_retryer_test.go b/aws/default_retryer_test.go deleted file mode 100644 index f8a1132554c..00000000000 --- a/aws/default_retryer_test.go +++ /dev/null @@ -1,200 +0,0 @@ -package aws - -import ( - "net/http" - "testing" - "time" -) - -func TestRetryThrottleStatusCodes(t *testing.T) { - cases := []struct { - expectThrottle bool - expectRetry bool - r Request - }{ - { - false, - false, - Request{ - HTTPResponse: &http.Response{StatusCode: 200}, - }, - }, - { - true, - true, - Request{ - HTTPResponse: &http.Response{StatusCode: 429}, - }, - }, - { - true, - true, - Request{ - HTTPResponse: &http.Response{StatusCode: 502}, - }, - }, - { - true, - true, - Request{ - HTTPResponse: &http.Response{StatusCode: 503}, - }, - }, - { - true, - true, - Request{ - HTTPResponse: &http.Response{StatusCode: 504}, - }, - }, - { - false, - true, - Request{ - HTTPResponse: &http.Response{StatusCode: 500}, - }, - }, - } - - d := NewDefaultRetryer(func(d *DefaultRetryer) { - d.NumMaxRetries = 100 - }) - for i, c := range cases { - throttle := c.r.IsErrorThrottle() - retry := d.ShouldRetry(&c.r) - - if e, a := c.expectThrottle, throttle; e != a { - t.Errorf("%d: expected %v, but received %v", i, e, a) - } - - if e, a := c.expectRetry, retry; e != a { - t.Errorf("%d: expected %v, but received %v", i, e, a) - } - } -} - -func TestGetRetryAfterDelay(t *testing.T) { - cases := []struct { - r Request - e bool - }{ - { - Request{ - HTTPResponse: &http.Response{StatusCode: 200}, - }, - false, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 500}, - }, - false, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 429}, - }, - true, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 503}, - }, - true, - }, - } - - for i, c := range cases { - a := canUseRetryAfterHeader(&c.r) - if c.e != a { - t.Errorf("%d: expected %v, but received %v", i, c.e, a) - } - } -} - -func TestGetRetryDelay(t *testing.T) { - cases := []struct { - r Request - e time.Duration - equal bool - ok bool - }{ - { - Request{ - HTTPResponse: &http.Response{StatusCode: 429, Header: http.Header{"Retry-After": []string{"3600"}}}, - }, - 3600 * time.Second, - true, - true, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}}, - }, - 120 * time.Second, - true, - true, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}}, - }, - 1 * time.Second, - false, - true, - }, - { - Request{ - HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}}, - }, - 0 * time.Second, - true, - false, - }, - } - - for i, c := range cases { - a, ok := getRetryAfterDelay(&c.r) - if c.ok != ok { - t.Errorf("%d: expected %v, but received %v", i, c.ok, ok) - } - - if (c.e != a) == c.equal { - t.Errorf("%d: expected %v, but received %v", i, c.e, a) - } - } -} - -func TestRetryDelay(t *testing.T) { - d := NewDefaultRetryer(func(d *DefaultRetryer) { - d.NumMaxRetries = 100 - }) - r := Request{} - for i := 0; i < 100; i++ { - rTemp := r - rTemp.HTTPResponse = &http.Response{StatusCode: 500, Header: http.Header{"Retry-After": []string{"299"}}} - rTemp.RetryCount = i - a := d.RetryRules(&rTemp) - if a > 5*time.Minute { - t.Errorf("retry delay should never be greater than five minutes, received %s for retrycount %d", a, i) - } - } - - for i := 0; i < 100; i++ { - rTemp := r - rTemp.RetryCount = i - rTemp.HTTPResponse = &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}} - a := d.RetryRules(&rTemp) - if a > 5*time.Minute { - t.Errorf("retry delay should not be greater than five minutes, received %s for retrycount %d", a, i) - } - } - - rTemp := r - rTemp.RetryCount = 1 - rTemp.HTTPResponse = &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"300"}}} - a := d.RetryRules(&rTemp) - if a < 5*time.Minute { - t.Errorf("retry delay should not be less than retry-after duration, received %s for retrycount %d", a, 1) - } -} diff --git a/aws/defaults/defaults.go b/aws/defaults/defaults.go index ad4fe57cab0..3689b419f85 100644 --- a/aws/defaults/defaults.go +++ b/aws/defaults/defaults.go @@ -72,9 +72,11 @@ func Handlers() aws.Handlers { handlers.Build.PushBackNamed(AddHostExecEnvUserAgentHander) handlers.Build.AfterEachFn = aws.HandlerListStopOnError handlers.Sign.PushBackNamed(BuildContentLengthHandler) + handlers.Send.PushFrontNamed(RequestInvocationIDHeaderHandler) + handlers.Send.PushFrontNamed(RetryMetricHeaderHandler) handlers.Send.PushBackNamed(ValidateReqSigHandler) handlers.Send.PushBackNamed(SendHandler) - handlers.AfterRetry.PushBackNamed(AfterRetryHandler) + handlers.ShouldRetry.PushBackNamed(RetryableCheckHandler) handlers.ValidateResponse.PushBackNamed(ValidateResponseHandler) return handlers diff --git a/aws/defaults/handlers.go b/aws/defaults/handlers.go index 3f97e3a90ee..8827dc0989d 100644 --- a/aws/defaults/handlers.go +++ b/aws/defaults/handlers.go @@ -9,11 +9,11 @@ import ( "net/url" "regexp" "strconv" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" - "github.com/aws/aws-sdk-go-v2/internal/sdk" ) // Interface for matching types which also have a Len method. @@ -134,6 +134,7 @@ func handleSendError(r *aws.Request, err error) { if r.HTTPResponse != nil { r.HTTPResponse.Body.Close() } + // Capture the case where url.Error is returned for error processing // response. e.g. 301 without location header comes back as string // error and r.HTTPResponse is nil. Other URL redirect errors will @@ -161,55 +162,84 @@ func handleSendError(r *aws.Request, err error) { // Catch all request errors, and let the retryer determine // if the error is retryable. - r.Error = awserr.New("RequestError", "send request failed", err) + r.Error = &aws.RequestSendError{Response: r.HTTPResponse, Err: err} // Override the error with a context canceled error, if that was canceled. ctx := r.Context() select { case <-ctx.Done(): - r.Error = awserr.New(aws.ErrCodeRequestCanceled, - "request context canceled", ctx.Err()) - r.Retryable = aws.Bool(false) + r.Error = &aws.RequestCanceledError{Err: ctx.Err()} default: } } // ValidateResponseHandler is a request handler to validate service response. -var ValidateResponseHandler = aws.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *aws.Request) { - if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 { - // this may be replaced by an UnmarshalError handler - r.Error = awserr.New("UnknownError", "unknown error", nil) - } -}} +var ValidateResponseHandler = aws.NamedHandler{ + Name: "core.ValidateResponseHandler", + Fn: func(r *aws.Request) { + if r.HTTPResponse.StatusCode >= 300 { + // This may be replaced by a protocol's UnmarshalError handler + r.Error = &aws.HTTPResponseError{Response: r.HTTPResponse} + } + }} -// AfterRetryHandler performs final checks to determine if the request should -// be retried and how long to delay. -var AfterRetryHandler = aws.NamedHandler{ - Name: "core.AfterRetryHandler", +// RequestInvocationIDHeaderHandler sets the invocation id header for request +// tracking across attempts. +var RequestInvocationIDHeaderHandler = aws.NamedHandler{ + Name: "core.RequestInvocationIDHeaderHandler", Fn: func(r *aws.Request) { - // set retry state based on the service's state - r.Retryable = aws.Bool(r.Retryer.ShouldRetry(r)) + const invocationIDHeader = "amz-sdk-invocation-id" + r.HTTPRequest.Header.Set(invocationIDHeader, r.InvocationID) + }} - if r.WillRetry() { - r.RetryDelay = r.Retryer.RetryRules(r) +// RetryMetricHeaderHandler sets an additional header to the API request that +// includes retry details for the service to consider. +var RetryMetricHeaderHandler = aws.NamedHandler{ + Name: "core.RetryMetricHeaderHandler", + Fn: func(r *aws.Request) { + const retryMetricHeader = "amz-sdk-request" + var parts []string - if err := sdk.SleepWithContext(r.Context(), r.RetryDelay); err != nil { - r.Error = awserr.New(aws.ErrCodeRequestCanceled, - "request context canceled", err) - r.Retryable = aws.Bool(false) - return - } + parts = append(parts, fmt.Sprintf("attempt=%d", r.AttemptNum)) + if max := r.Retryer.MaxAttempts(); max != 0 { + parts = append(parts, fmt.Sprintf("max=%d", max)) + } + // TODO "ttl=YYYYmmddTHHMMSSZ" + // ttl = current_time + socket_read_timeout + estimated_skew + // SDK doesn't implement clock skew yet and not obvious how to obtain + // read deadlines. + + r.HTTPRequest.Header.Set("amz-sdk-request", strings.Join(parts, "; ")) + }} - // when the expired token exception occurs the credentials - // need to be expired locally so that the next request to - // get credentials will trigger a credentials refresh. - if p, ok := r.Config.Credentials.(sdk.Invalidator); ok && r.IsErrorExpired() { - p.Invalidate() +// RetryableCheckHandler performs final checks to determine if the request should +// be retried and how long to delay. +var RetryableCheckHandler = aws.NamedHandler{ + Name: "core.RetryableCheckHandler", + Fn: func(r *aws.Request) { + r.ShouldRetry = false + + retryable := r.Retryer.IsErrorRetryable(r.Error) + if !retryable { + return + } + + if max := r.Retryer.MaxAttempts(); max > 0 && r.AttemptNum >= max { + r.Error = &aws.MaxAttemptsError{ + Attempt: r.AttemptNum, + Err: r.Error, } + return + } - r.RetryCount++ - r.Error = nil + var err error + r.RetryDelay, err = r.Retryer.RetryDelay(r.AttemptNum, r.Error) + if err != nil { + r.Error = err + return } + + r.ShouldRetry = true }} // ValidateEndpointHandler is a request handler to validate a request had the diff --git a/aws/defaults/handlers_test.go b/aws/defaults/handlers_test.go index 421e4c2e0e8..f0ff3993d41 100644 --- a/aws/defaults/handlers_test.go +++ b/aws/defaults/handlers_test.go @@ -3,6 +3,7 @@ package defaults_test import ( "bytes" "context" + "errors" "fmt" "io/ioutil" "net/http" @@ -13,11 +14,10 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" - "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/aws-sdk-go-v2/service/s3" ) @@ -60,117 +60,24 @@ func TestValidateEndpointHandlerErrorRegion(t *testing.T) { } } -type mockCredsProvider struct { - retrieveCalled bool - invalidateCalled bool -} - -func (m *mockCredsProvider) Retrieve(ctx context.Context) (aws.Credentials, error) { - m.retrieveCalled = true - return aws.Credentials{Source: "mockCredsProvider"}, nil -} - -func (m *mockCredsProvider) Invalidate() { - m.invalidateCalled = true -} - -func TestAfterRetry_RefreshCreds(t *testing.T) { - orig := sdk.SleepWithContext - defer func() { sdk.SleepWithContext = orig }() - sdk.SleepWithContext = func(context.Context, time.Duration) error { return nil } - - credProvider := &mockCredsProvider{} - - cfg := unit.Config() - cfg.Credentials = credProvider - - svc := awstesting.NewClient(cfg) - req := svc.NewRequest(&aws.Operation{Name: "Operation"}, nil, nil) - req.Retryable = aws.Bool(true) - req.Error = awserr.New("ExpiredTokenException", "", nil) - req.HTTPResponse = &http.Response{ - StatusCode: 403, - } - - defaults.AfterRetryHandler.Fn(req) - - if !credProvider.invalidateCalled { - t.Errorf("expect credentials to be invalidated") - } -} - -func TestAfterRetry_NoPanicRefreshStaticCreds(t *testing.T) { - orig := sdk.SleepWithContext - defer func() { sdk.SleepWithContext = orig }() - sdk.SleepWithContext = func(context.Context, time.Duration) error { return nil } - - credProvider := aws.NewStaticCredentialsProvider("AKID", "SECRET", "") - - cfg := unit.Config() - cfg.Credentials = credProvider - - svc := awstesting.NewClient(cfg) - req := svc.NewRequest(&aws.Operation{Name: "Operation"}, nil, nil) - req.Retryable = aws.Bool(true) - req.Error = awserr.New("ExpiredTokenException", "", nil) - req.HTTPResponse = &http.Response{ - StatusCode: 403, - } - - defaults.AfterRetryHandler.Fn(req) -} - -func TestAfterRetryWithContextCanceled(t *testing.T) { +func TestShouldRetry_WithContext(t *testing.T) { c := awstesting.NewClient(unit.Config()) - - req := c.NewRequest(&aws.Operation{Name: "Operation"}, nil, nil) - ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} - req.SetContext(ctx) - - req.Error = fmt.Errorf("some error") - req.Retryable = aws.Bool(true) - req.HTTPResponse = &http.Response{ - StatusCode: 500, - } - - close(ctx.DoneCh) - ctx.Error = fmt.Errorf("context canceled") - - defaults.AfterRetryHandler.Fn(req) - - if req.Error == nil { - t.Fatalf("expect error but didn't receive one") - } - - aerr := req.Error.(awserr.Error) - - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expect %q, error code got %q", e, a) - } -} - -func TestAfterRetryWithContext(t *testing.T) { - c := awstesting.NewClient(unit.Config()) req := c.NewRequest(&aws.Operation{Name: "Operation"}, nil, nil) - - ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} req.SetContext(ctx) - req.Error = fmt.Errorf("some error") - req.Retryable = aws.Bool(true) - req.HTTPResponse = &http.Response{ - StatusCode: 500, + req.Error = &aws.HTTPResponseError{ + Response: &http.Response{ + StatusCode: 500, + Header: http.Header{}, + }, } - defaults.AfterRetryHandler.Fn(req) + defaults.RetryableCheckHandler.Fn(req) - if req.Error != nil { - t.Fatalf("expect no error, got %v", req.Error) - } - if e, a := 1, req.RetryCount; e != a { - t.Errorf("expect retry count to be %d, got %d", e, a) + if req.RetryDelay == 0 { + t.Fatalf("expect retry delay got none") } } @@ -182,12 +89,6 @@ func TestSendWithContextCanceled(t *testing.T) { ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} req.SetContext(ctx) - req.Error = fmt.Errorf("some error") - req.Retryable = aws.Bool(true) - req.HTTPResponse = &http.Response{ - StatusCode: 500, - } - close(ctx.DoneCh) ctx.Error = fmt.Errorf("context canceled") @@ -197,10 +98,9 @@ func TestSendWithContextCanceled(t *testing.T) { t.Fatalf("expect error but didn't receive one") } - aerr := req.Error.(awserr.Error) - - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expect %q, error code got %q", e, a) + var aerr *aws.RequestCanceledError + if !errors.As(req.Error, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, req.Error) } } @@ -428,3 +328,63 @@ func TestSendHandler_HEADNoBody(t *testing.T) { t.Errorf("expect %d status code, got %d", e, a) } } + +func TestRequestInvocationIDHeaderHandler(t *testing.T) { + cfg := unit.Config() + r := aws.New(cfg, aws.Metadata{}, cfg.Handlers, aws.NoOpRetryer{}, &aws.Operation{}, + &struct{}{}, struct{}{}) + + if len(r.InvocationID) == 0 { + t.Fatalf("expect invocation id, got none") + } + + defaults.RequestInvocationIDHeaderHandler.Fn(r) + if r.Error != nil { + t.Fatalf("expect no error, got %v", r.Error) + } + + if e, a := r.InvocationID, r.HTTPRequest.Header.Get("amz-sdk-invocation-id"); e != a { + t.Errorf("expect %v invocation id, got %v", e, a) + } +} + +func TestRetryMetricHeaderHandler(t *testing.T) { + cases := map[string]struct { + Attempt int + MaxAttempts int + Expect string + }{ + "first attempt": { + Attempt: 1, MaxAttempts: 3, + Expect: "attempt=1; max=3", + }, + "last attempt": { + Attempt: 3, MaxAttempts: 3, + Expect: "attempt=3; max=3", + }, + "no max attempt": { + Attempt: 10, + Expect: "attempt=10", + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + cfg := unit.Config() + r := aws.New(cfg, aws.Metadata{}, cfg.Handlers, aws.NoOpRetryer{}, + &aws.Operation{}, &struct{}{}, struct{}{}) + + r.AttemptNum = c.Attempt + r.Retryer = retry.AddWithMaxAttempts(r.Retryer, c.MaxAttempts) + + defaults.RetryMetricHeaderHandler.Fn(r) + if r.Error != nil { + t.Fatalf("expect no error, got %v", r.Error) + } + + if e, a := c.Expect, r.HTTPRequest.Header.Get("amz-sdk-request"); e != a { + t.Errorf("expect %q metric, got %q", e, a) + } + }) + } +} diff --git a/aws/defaults/param_validator_test.go b/aws/defaults/param_validator_test.go index 7cf25ba4470..0c086d2bb13 100644 --- a/aws/defaults/param_validator_test.go +++ b/aws/defaults/param_validator_test.go @@ -1,6 +1,7 @@ package defaults_test import ( + "errors" "fmt" "reflect" "testing" @@ -128,7 +129,11 @@ func TestMissingRequiredParameters(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } - errs := req.Error.(awserr.BatchedErrors).OrigErrs() + var berr awserr.BatchedErrors + if !errors.As(req.Error, &berr) { + t.Fatalf("expect %T error, got %v", berr, req.Error) + } + errs := berr.Errs() if e, a := 3, len(errs); e != a { t.Errorf("expect %v, got %v", e, a) } @@ -171,7 +176,11 @@ func TestNestedMissingRequiredParameters(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } - errs := req.Error.(awserr.BatchedErrors).OrigErrs() + var berr awserr.BatchedErrors + if !errors.As(req.Error, &berr) { + t.Fatalf("expect %T error, got %v", berr, req.Error) + } + errs := berr.Errs() if e, a := 3, len(errs); e != a { t.Errorf("expect %v, got %v", e, a) } diff --git a/aws/ec2metadata/api_client.go b/aws/ec2metadata/api_client.go index 887e741161e..14b065d5fa3 100644 --- a/aws/ec2metadata/api_client.go +++ b/aws/ec2metadata/api_client.go @@ -11,6 +11,7 @@ import ( "bytes" "context" "errors" + "fmt" "io" "net" "net/http" @@ -22,6 +23,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" ) const ( @@ -96,6 +98,11 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + svc.Retryer = retry.AddWithMaxBackoffDelay(svc.Retryer, 1*time.Second) + // token provider instance tp := newTokenProvider(svc, defaultTTL) // NamedHandler for fetching token @@ -141,10 +148,9 @@ func New(config aws.Config) *Client { r.HTTPResponse = &http.Response{ Header: http.Header{}, } - r.Error = awserr.New( - aws.ErrCodeRequestCanceled, - "EC2 IMDS access disabled via "+disableServiceEnvVar+" env var", - nil) + r.Error = &aws.RequestCanceledError{ + Err: fmt.Errorf("EC2 IMDS access disabled via " + disableServiceEnvVar + " env var"), + } }, }) } diff --git a/aws/ec2metadata/api_client_test.go b/aws/ec2metadata/api_client_test.go index 397bfe47599..8f65c6e3a0a 100644 --- a/aws/ec2metadata/api_client_test.go +++ b/aws/ec2metadata/api_client_test.go @@ -2,12 +2,12 @@ package ec2metadata_test import ( "context" + "errors" "os" "strings" "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/ec2metadata" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -32,11 +32,12 @@ func TestClientDisableIMDS(t *testing.T) { t.Errorf("expect no response, got %v", resp) } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expect %v error code, got %v", e, a) + var ce *aws.RequestCanceledError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := "AWS_EC2_METADATA_DISABLED", aerr.Message(); !strings.Contains(a, e) { + + if e, a := "AWS_EC2_METADATA_DISABLED", ce.Err.Error(); !strings.Contains(a, e) { t.Errorf("expect %v in error message, got %v", e, a) } } diff --git a/aws/ec2metadata/api_ops_test.go b/aws/ec2metadata/api_ops_test.go index aa205eeb84b..7cd10af7f60 100644 --- a/aws/ec2metadata/api_ops_test.go +++ b/aws/ec2metadata/api_ops_test.go @@ -19,6 +19,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/ec2metadata" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" + "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/google/go-cmp/cmp" ) @@ -620,7 +621,15 @@ func TestMetadataIAMInfo_failure(t *testing.T) { } } +type retryableError struct{} + +func (retryableError) Error() string { return "retryable error" } +func (retryableError) RetryableError() bool { return true } + func TestMetadataNotAvailable(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() + defer restoreSleep() + c := ec2metadata.New(unit.Config()) c.Handlers.Send.Clear() c.Handlers.Send.PushBack(func(r *aws.Request) { @@ -629,8 +638,7 @@ func TestMetadataNotAvailable(t *testing.T) { Status: http.StatusText(int(0)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } - r.Error = awserr.New("RequestError", "send request failed", nil) - r.Retryable = aws.Bool(true) // network errors are retryable + r.Error = &aws.RequestSendError{Response: r.HTTPResponse, Err: retryableError{}} }) if c.Available(context.Background()) { @@ -647,7 +655,6 @@ func TestMetadataErrorResponse(t *testing.T) { Status: http.StatusText(http.StatusBadRequest), Body: ioutil.NopCloser(strings.NewReader("error message text")), } - r.Retryable = aws.Bool(false) // network errors are retryable }) data, err := c.GetMetadata(context.Background(), "uri/path") @@ -734,6 +741,9 @@ func TestEC2RoleProviderInstanceIdentity(t *testing.T) { } func TestEC2MetadataRetryFailure(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() + defer restoreSleep() + mux := http.NewServeMux() mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) { @@ -761,12 +771,9 @@ func TestEC2MetadataRetryFailure(t *testing.T) { cfg := unit.Config() cfg.EndpointResolver = aws.EndpointResolverFunc(myCustomResolver) c := ec2metadata.New(cfg) - // mock retryer with minimum throttle delay set to 1 ms - c.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.MinThrottleDelay = 1 * time.Millisecond - }) + // Handler on client that logs if retried - c.Handlers.AfterRetry.PushBack(func(i *aws.Request) { + c.Handlers.ShouldRetry.PushBack(func(i *aws.Request) { t.Logf("%v received, retrying operation %v", i.HTTPResponse.StatusCode, i.Operation.Name) }) c.Handlers.Complete.PushBack(func(i *aws.Request) { @@ -791,6 +798,9 @@ func TestEC2MetadataRetryFailure(t *testing.T) { } func TestEC2MetadataRetryOnce(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() + defer restoreSleep() + var secureDataFlow bool var retry = true mux := http.NewServeMux() @@ -828,12 +838,9 @@ func TestEC2MetadataRetryOnce(t *testing.T) { cfg := unit.Config() cfg.EndpointResolver = aws.EndpointResolverFunc(myCustomResolver) c := ec2metadata.New(cfg) - // mock retryer with minimum throttle delay set to 1 ms - c.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.MinThrottleDelay = 1 * time.Millisecond - }) + // Handler on client that logs if retried - c.Handlers.AfterRetry.PushBack(func(i *aws.Request) { + c.Handlers.ShouldRetry.PushBack(func(i *aws.Request) { t.Logf("%v received, retrying operation %v", i.HTTPResponse.StatusCode, i.Operation.Name) tokenRetryCount++ }) @@ -1054,6 +1061,9 @@ func TestExhaustiveRetryWith401(t *testing.T) { } func TestRequestTimeOut(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() + defer restoreSleep() + mux := http.NewServeMux() done := make(chan bool) mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) { @@ -1091,48 +1101,59 @@ func TestRequestTimeOut(t *testing.T) { if httpclient, ok := cfg.HTTPClient.(httpClientTransportOptions); ok { c.Config.HTTPClient = httpclient.WithTransportOptions(func(tr *http.Transport) { - tr.ResponseHeaderTimeout = 100 * time.Millisecond + tr.ResponseHeaderTimeout = 10 * time.Millisecond }) } - c.Handlers.Complete.PushBack(op.addToOperationPerformedList) - start := time.Now() + var retryDelays []time.Duration + c.Handlers.ShouldRetry.PushBack(func(r *aws.Request) { + if r.ShouldRetry { + retryDelays = append(retryDelays, r.RetryDelay) + } + }) + + c.Handlers.CompleteAttempt.PushBack(op.addToOperationPerformedList) + resp, err := c.GetMetadata(context.Background(), "/some/path") + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } - if e, a := 1*time.Second, time.Since(start); e < a { - t.Fatalf("expected duration of test to be less than %v, got %v", e, a) + if e, a := 2, len(retryDelays); e != a { + t.Errorf("expect %v retries, got %v", e, a) + } + for _, d := range retryDelays { + if e, a := 1*time.Second, d; a > d { + t.Errorf("expect %v max retry delay, got %v", e, a) + } } - expectedOperationsPerformed := []string{"GetToken", "GetMetadata"} + expectedOperationsPerformed := []string{"GetToken", "GetToken", "GetToken", "GetMetadata"} if e, a := "IMDSProfileForSDKGo", resp; e != a { t.Fatalf("Expected %v, got %v", e, a) } - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if diff := cmp.Diff(op.operationsPerformed, expectedOperationsPerformed); diff != "" { t.Fatalf("Found diff in operations performed: \n %v \n", diff) } - start = time.Now() + retryDelays = nil resp, err = c.GetMetadata(context.Background(), "/some/path") - if e, a := 1*time.Second, time.Since(start); e < a { - t.Fatalf("expected duration of test to be less than %v, got %v", e, a) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + if e, a := 0, len(retryDelays); e != a { + t.Errorf("expect %v retries, got %v", e, a) } - expectedOperationsPerformed = []string{"GetToken", "GetMetadata", "GetMetadata"} + expectedOperationsPerformed = append(expectedOperationsPerformed, "GetMetadata") if e, a := "IMDSProfileForSDKGo", resp; e != a { t.Fatalf("Expected %v, got %v", e, a) } - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if diff := cmp.Diff(op.operationsPerformed, expectedOperationsPerformed); diff != "" { t.Fatalf("Found diff in operations performed: \n %v \n", diff) } diff --git a/aws/ec2metadata/token_provider.go b/aws/ec2metadata/token_provider.go index 380b003ce8e..5a02f6a1012 100644 --- a/aws/ec2metadata/token_provider.go +++ b/aws/ec2metadata/token_provider.go @@ -1,6 +1,7 @@ package ec2metadata import ( + "errors" "net/http" "sync/atomic" "time" @@ -48,19 +49,23 @@ func (t *tokenProvider) fetchTokenHandler(r *aws.Request) { output, err := t.client.getToken(r.Context(), t.configuredTTL) if err != nil { // change the disabled flag on token provider to true, when error is request timeout error. - if requestFailureError, ok := err.(awserr.RequestFailure); ok { - switch requestFailureError.StatusCode() { - case http.StatusForbidden, http.StatusNotFound, http.StatusMethodNotAllowed: + if rf, ok := err.(awserr.RequestFailure); ok { + switch rf.StatusCode() { + case http.StatusForbidden, + http.StatusNotFound, + http.StatusMethodNotAllowed: + atomic.StoreUint32(&t.disabled, 1) + case http.StatusBadRequest: - r.Error = requestFailureError + r.Error = rf } // Check if request timed out while waiting for response - if e, ok := requestFailureError.OrigErr().(awserr.Error); ok { - if e.Code() == "RequestError" { - atomic.StoreUint32(&t.disabled, 1) - } + var re *aws.RequestSendError + var ce *aws.RequestCanceledError + if errors.As(rf, &re) || errors.As(rf, &ce) { + atomic.StoreUint32(&t.disabled, 1) } } return diff --git a/aws/ec2rolecreds/provider_test.go b/aws/ec2rolecreds/provider_test.go index 3e5d470adcd..fb9dd38f94a 100644 --- a/aws/ec2rolecreds/provider_test.go +++ b/aws/ec2rolecreds/provider_test.go @@ -2,6 +2,7 @@ package ec2rolecreds_test import ( "context" + "errors" "fmt" "net/http" "net/http/httptest" @@ -98,16 +99,20 @@ func TestProvider_FailAssume(t *testing.T) { t.Fatalf("expect error, got none") } - e := err.(awserr.Error) - if e, a := "ErrorCode", e.Code(); e != a { + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", err, aerr) + } + if e, a := "ErrorCode", aerr.Code(); e != a { t.Errorf("expect %v code, got %v", e, a) } - if e, a := "ErrorMsg", e.Message(); e != a { + if e, a := "ErrorMsg", aerr.Message(); e != a { t.Errorf("expect %v message, got %v", e, a) } - if err := e.OrigErr(); err != nil { - t.Fatalf("expect no error, got %v", err) + nestedErr := errors.Unwrap(aerr) + if nestedErr != nil { + t.Fatalf("expect no nested error, got %v", err) } if e, a := "", creds.AccessKeyID; e != a { diff --git a/aws/endpointcreds/provider_test.go b/aws/endpointcreds/provider_test.go index 89d0dc8cf10..08652b6b27d 100644 --- a/aws/endpointcreds/provider_test.go +++ b/aws/endpointcreds/provider_test.go @@ -3,6 +3,7 @@ package endpointcreds_test import ( "context" "encoding/json" + "errors" "fmt" "net/http" "net/http/httptest" @@ -144,7 +145,10 @@ func TestFailedRetrieveCredentials(t *testing.T) { t.Fatalf("expect error, got none") } - aerr := err.(awserr.Error) + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", err, aerr) + } if e, a := "CredentialsEndpointError", aerr.Code(); e != a { t.Errorf("expect %v, got %v", e, a) } @@ -152,7 +156,13 @@ func TestFailedRetrieveCredentials(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } - aerr = aerr.OrigErr().(awserr.Error) + err = errors.Unwrap(aerr) + if err == nil { + t.Fatalf("expect nested error, got none") + } + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", err, aerr) + } if e, a := "Error", aerr.Code(); e != a { t.Errorf("expect %v, got %v", e, a) } diff --git a/aws/endpoints/decode.go b/aws/endpoints/decode.go index a38185f0653..378be9a6456 100644 --- a/aws/endpoints/decode.go +++ b/aws/endpoints/decode.go @@ -4,8 +4,6 @@ import ( "encoding/json" "fmt" "io" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" ) type modelDefinition map[string]json.RawMessage @@ -138,11 +136,18 @@ func custSetUnresolveServices(p *partition) { } type decodeModelError struct { - awsError + reason string + err error } -func newDecodeModelError(msg string, err error) decodeModelError { - return decodeModelError{ - awsError: awserr.New("DecodeEndpointsModelError", msg, err), - } +func newDecodeModelError(msg string, err error) *decodeModelError { + return &decodeModelError{reason: msg, err: err} +} + +func (d *decodeModelError) Error() string { + return fmt.Sprintf("failed to decode model, %v, %v", d.reason, d.err) +} + +func (d *decodeModelError) Unwrap() error { + return d.err } diff --git a/aws/endpoints/endpoints.go b/aws/endpoints/endpoints.go index d364d10d47a..b0d29295611 100644 --- a/aws/endpoints/endpoints.go +++ b/aws/endpoints/endpoints.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" ) // ResolveOptions provide the configuration needed to direct how the @@ -268,15 +267,10 @@ func (e Endpoint) Resolve(opts ResolveOptions) (aws.Endpoint, error) { return e.p.EndpointFor(e.serviceID, e.id, opts) } -// So that the Error interface type can be included as an anonymous field -// in the requestError struct and not conflict with the error.Error() method. -type awsError awserr.Error - // A UnknownServiceError is returned when the service does not resolve to an // endpoint. Includes a list of all known services for the partition. Returned // when a partition does not support the service. type UnknownServiceError struct { - awsError Partition string Service string Known []string @@ -285,8 +279,6 @@ type UnknownServiceError struct { // NewUnknownServiceError builds and returns UnknownServiceError. func NewUnknownServiceError(p, s string, known []string) UnknownServiceError { return UnknownServiceError{ - awsError: awserr.New("UnknownServiceError", - "could not resolve endpoint for unknown service", nil), Partition: p, Service: s, Known: known, @@ -295,24 +287,17 @@ func NewUnknownServiceError(p, s string, known []string) UnknownServiceError { // String returns the string representation of the error. func (e UnknownServiceError) Error() string { - extra := fmt.Sprintf("partition: %q, service: %q", - e.Partition, e.Service) + extra := fmt.Sprintf("partition: %q, service: %q", e.Partition, e.Service) if len(e.Known) > 0 { extra += fmt.Sprintf(", known: %v", e.Known) } - return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr()) -} - -// String returns the string representation of the error. -func (e UnknownServiceError) String() string { - return e.Error() + return "unknown service, could not resolve endpoint, " + extra } // A UnknownEndpointError is returned when in StrictMatching mode and the // service is valid, but the region does not resolve to an endpoint. Includes // a list of all known endpoints for the service. type UnknownEndpointError struct { - awsError Partition string Service string Region string @@ -322,8 +307,6 @@ type UnknownEndpointError struct { // NewUnknownEndpointError builds and returns UnknownEndpointError. func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError { return UnknownEndpointError{ - awsError: awserr.New("UnknownEndpointError", - "could not resolve endpoint", nil), Partition: p, Service: s, Region: r, @@ -338,10 +321,5 @@ func (e UnknownEndpointError) Error() string { if len(e.Known) > 0 { extra += fmt.Sprintf(", known: %v", e.Known) } - return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr()) -} - -// String returns the string representation of the error. -func (e UnknownEndpointError) String() string { - return e.Error() + return "unknown endpoint, could not resolve endpoint, " + extra } diff --git a/aws/handlers.go b/aws/handlers.go index f464b9c9ab0..a403fc6f4ae 100644 --- a/aws/handlers.go +++ b/aws/handlers.go @@ -16,8 +16,7 @@ type Handlers struct { Unmarshal HandlerList UnmarshalMeta HandlerList UnmarshalError HandlerList - Retry HandlerList - AfterRetry HandlerList + ShouldRetry HandlerList CompleteAttempt HandlerList Complete HandlerList } @@ -33,8 +32,7 @@ func (h *Handlers) Copy() Handlers { Unmarshal: h.Unmarshal.copy(), UnmarshalError: h.UnmarshalError.copy(), UnmarshalMeta: h.UnmarshalMeta.copy(), - Retry: h.Retry.copy(), - AfterRetry: h.AfterRetry.copy(), + ShouldRetry: h.ShouldRetry.copy(), CompleteAttempt: h.CompleteAttempt.copy(), Complete: h.Complete.copy(), } @@ -50,8 +48,7 @@ func (h *Handlers) Clear() { h.UnmarshalMeta.Clear() h.UnmarshalError.Clear() h.ValidateResponse.Clear() - h.Retry.Clear() - h.AfterRetry.Clear() + h.ShouldRetry.Clear() h.CompleteAttempt.Clear() h.Complete.Clear() } diff --git a/aws/http_request_retry_test.go b/aws/http_request_retry_test.go index e337a5e1330..b01ddcf8392 100644 --- a/aws/http_request_retry_test.go +++ b/aws/http_request_retry_test.go @@ -4,7 +4,6 @@ import ( "context" "strings" "testing" - "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/internal/awstesting/mock" @@ -13,15 +12,11 @@ import ( ) func TestRequestCancelRetry(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() - reqNum := 0 + var reqNum int cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 1 - }) - s := mock.NewMockClient(cfg) s.Handlers.Validate.Clear() @@ -32,6 +27,7 @@ func TestRequestCancelRetry(t *testing.T) { reqNum++ }) out := &testData{} + ctx, cancelFn := context.WithCancel(context.Background()) r := s.NewRequest(&aws.Operation{Name: "Operation"}, nil, out) r.SetContext(ctx) @@ -45,16 +41,3 @@ func TestRequestCancelRetry(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } } - -func mockSleep() func() { - origSleep := sdk.Sleep - sdk.Sleep = func(time.Duration) {} - - origCtxSleep := sdk.SleepWithContext - sdk.SleepWithContext = func(context.Context, time.Duration) error { return nil } - - return func() { - sdk.Sleep = origSleep - sdk.SleepWithContext = origCtxSleep - } -} diff --git a/aws/no_op_retryer.go b/aws/no_op_retryer.go deleted file mode 100644 index e0294dabcae..00000000000 --- a/aws/no_op_retryer.go +++ /dev/null @@ -1,24 +0,0 @@ -package aws - -import "time" - -// NoOpRetryer provides a retryer that performs no retries. -// It should be used when we do not want retries to be performed. -type NoOpRetryer struct{} - -// MaxRetries returns the number of maximum returns the service will use to make -// an individual API; For NoOpRetryer the MaxRetries will always be zero. -func (d NoOpRetryer) MaxRetries() int { - return 0 -} - -// ShouldRetry will always return false for NoOpRetryer, as it should never retry. -func (d NoOpRetryer) ShouldRetry(_ *Request) bool { - return false -} - -// RetryRules returns the delay duration before retrying this request again; -// since NoOpRetryer does not retry, RetryRules always returns 0. -func (d NoOpRetryer) RetryRules(_ *Request) time.Duration { - return 0 -} diff --git a/aws/no_op_retryer_test.go b/aws/no_op_retryer_test.go deleted file mode 100644 index dec439393e9..00000000000 --- a/aws/no_op_retryer_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package aws - -import ( - "net/http" - "testing" - "time" -) - -func TestNoOpRetryer(t *testing.T) { - cases := []struct { - r Request - expectMaxRetries int - expectRetryDelay time.Duration - expectRetry bool - }{ - { - r: Request{ - HTTPResponse: &http.Response{StatusCode: 200}, - }, - expectMaxRetries: 0, - expectRetryDelay: 0, - expectRetry: false, - }, - } - - d := NoOpRetryer{} - for i, c := range cases { - maxRetries := d.MaxRetries() - retry := d.ShouldRetry(&c.r) - retryDelay := d.RetryRules(&c.r) - - if e, a := c.expectMaxRetries, maxRetries; e != a { - t.Errorf("%d: expected %v, but received %v for number of max retries", i, e, a) - } - - if e, a := c.expectRetry, retry; e != a { - t.Errorf("%d: expected %v, but received %v for should retry", i, e, a) - } - - if e, a := c.expectRetryDelay, retryDelay; e != a { - t.Errorf("%d: expected %v, but received %v as retry delay", i, e, a) - } - } -} diff --git a/aws/ratelimit/token_bucket.go b/aws/ratelimit/token_bucket.go new file mode 100644 index 00000000000..f337803f2c1 --- /dev/null +++ b/aws/ratelimit/token_bucket.go @@ -0,0 +1,51 @@ +package ratelimit + +import ( + "sync" +) + +// TokenBucket provides a concurrency safe utility for adding and removing +// tokens from the available token bucket. +type TokenBucket struct { + capacity uint + maxCapacity uint + mu sync.Mutex +} + +// NewTokenBucket returns an initialized TokenBucket with the capacity +// specified. +func NewTokenBucket(i uint) *TokenBucket { + return &TokenBucket{ + capacity: i, + maxCapacity: i, + } +} + +// Retrieve attempts to reduce the available tokens by the amount requested. If +// there are tokens available true will be returned along with the number of +// available tokens remaining. If amount requested is larger than the available +// capacity, false will be returned along with the available capacity. If the +// amount is less than the available capacity +func (t *TokenBucket) Retrieve(amount uint) (available uint, retrieved bool) { + t.mu.Lock() + defer t.mu.Unlock() + + if amount > t.capacity { + return t.capacity, false + } + + t.capacity -= amount + return t.capacity, true +} + +// Refund returns the amount of tokens back to the available token bucket, up +// to the initial capacity. +func (t *TokenBucket) Refund(amount uint) { + t.mu.Lock() + defer t.mu.Unlock() + + t.capacity += amount + if t.capacity > t.maxCapacity { + t.capacity = t.maxCapacity + } +} diff --git a/aws/ratelimit/token_rate_limit.go b/aws/ratelimit/token_rate_limit.go new file mode 100644 index 00000000000..d7997f42aca --- /dev/null +++ b/aws/ratelimit/token_rate_limit.go @@ -0,0 +1,82 @@ +package ratelimit + +import ( + "context" + "fmt" +) + +type rateToken struct { + tokenCost uint + bucket *TokenBucket +} + +func (t rateToken) release() error { + t.bucket.Refund(t.tokenCost) + return nil +} + +// TokenRateLimit provides a Token Bucket RateLimiter implementation +// that limits the overall number of retry attempts that can be made across +// operation invocations. +type TokenRateLimit struct { + bucket *TokenBucket +} + +// NewTokenRateLimit returns an TokenRateLimit with default values. +// Functional options can configure the retry rate limiter. +func NewTokenRateLimit(tokens uint) *TokenRateLimit { + return &TokenRateLimit{ + bucket: NewTokenBucket(tokens), + } +} + +func isTimeoutError(error) bool { + return false +} + +type canceledError struct { + Err error +} + +func (c canceledError) CanceledError() bool { return true } +func (c canceledError) Unwrap() error { return c.Err } +func (c canceledError) Error() string { + return fmt.Sprintf("canceled, %v", c.Err) +} + +// GetToken may cause a available pool of retry quota to be +// decremented. Will return an error if the decremented value can not be +// reduced from the retry quota. +func (l *TokenRateLimit) GetToken(ctx context.Context, cost uint) (func() error, error) { + select { + case <-ctx.Done(): + return nil, canceledError{Err: ctx.Err()} + default: + } + if avail, ok := l.bucket.Retrieve(cost); !ok { + return nil, QuotaExceededError{Available: avail, Requested: cost} + } + + return rateToken{ + tokenCost: cost, + bucket: l.bucket, + }.release, nil +} + +// AddTokens increments the token bucket by a fixed amount. +func (l *TokenRateLimit) AddTokens(v uint) error { + l.bucket.Refund(v) + return nil +} + +// QuotaExceededError provides the SDK error when the retries for a given +// token bucket have been exhausted. +type QuotaExceededError struct { + Available uint + Requested uint +} + +func (e QuotaExceededError) Error() string { + return fmt.Sprintf("retry quota exceeded, %d available, %d requested", + e.Available, e.Requested) +} diff --git a/aws/ratelimit/token_rate_limit_test.go b/aws/ratelimit/token_rate_limit_test.go new file mode 100644 index 00000000000..b8d0bc9e645 --- /dev/null +++ b/aws/ratelimit/token_rate_limit_test.go @@ -0,0 +1,89 @@ +package ratelimit + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" +) + +func TestTokenRateLimit(t *testing.T) { + type usage struct { + Cost uint + Release bool + Err string + AddTokens uint + } + + cases := map[string]struct { + Tokens uint + Usages []usage + }{ + "retrieve": { + Tokens: 10, + Usages: []usage{ + {Cost: 5, Release: true}, + {Cost: 5}, + {Cost: 5}, + {Cost: 5, Err: "retry quota exceeded"}, + {AddTokens: 5}, + {Cost: 5}, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + rl := NewTokenRateLimit(c.Tokens) + + for i, u := range c.Usages { + t.Run(fmt.Sprintf("usage_%d", i), func(t *testing.T) { + if u.Cost != 0 { + f, err := rl.GetToken(context.Background(), u.Cost) + if len(u.Err) != 0 { + if err == nil { + t.Fatalf("expect error, got none") + } + if e, a := u.Err, err.Error(); !strings.Contains(a, e) { + t.Fatalf("expect %q error, got %q", e, a) + } + } else if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if u.Release { + if err := f(); err != nil { + t.Fatalf("expect no error, got %v", err) + } + } + } + + if u.AddTokens != 0 { + rl.AddTokens(u.AddTokens) + } + }) + } + }) + } +} + +func TestTokenRateLimit_canceled(t *testing.T) { + rl := NewTokenRateLimit(10) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + fn, err := rl.GetToken(ctx, 1) + if err == nil { + t.Fatalf("expect error, got none") + } + if fn != nil { + t.Errorf("expect no release func returned") + } + + var v interface{ CanceledError() bool } + if !errors.As(err, &v) { + t.Fatalf("expect %T error, got %v", v, err) + } +} diff --git a/aws/request.go b/aws/request.go index 144c371a626..cdccab99971 100644 --- a/aws/request.go +++ b/aws/request.go @@ -12,6 +12,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/internal/sdk" ) const ( @@ -21,16 +22,78 @@ const ( // ErrCodeRead is an error that is returned during HTTP reads. ErrCodeRead = "ReadError" +) - // ErrCodeResponseTimeout is the connection timeout error that is received - // during body reads. - ErrCodeResponseTimeout = "ResponseTimeout" +// RequestSendError provides a generic request transport error. +type RequestSendError struct { + Response interface{} + Err error +} - // ErrCodeRequestCanceled is the error code that will be returned by an - // API request that was canceled. Requests given a Context may - // return this error when canceled. - ErrCodeRequestCanceled = "RequestCanceled" -) +// ConnectionError return that the error is related to not being able to send +// the request. +func (e *RequestSendError) ConnectionError() bool { + return true +} + +// Unwrap returns the underlying error, if there was one. +func (e *RequestSendError) Unwrap() error { + return e.Err +} + +func (e *RequestSendError) Error() string { + return fmt.Sprintf("request send failed, %v", e.Err) +} + +// HTTPResponseError provides the error type for an HTTP error response. +type HTTPResponseError struct { + Response *http.Response +} + +func (e *HTTPResponseError) Error() string { + return fmt.Sprintf("HTTP response error, %s, %d", + e.Response.Status, e.Response.StatusCode) +} + +// StatusCode returns the underlying status code for the request error. +func (e *HTTPResponseError) StatusCode() int { + return e.Response.StatusCode +} + +// MaxAttemptsError provides the error when the maximum number of attempts have +// been exceeded. +type MaxAttemptsError struct { + Attempt int + Err error +} + +func (e *MaxAttemptsError) Error() string { + return fmt.Sprintf("exceeded maximum number of attempts, %d, %v", e.Attempt, e.Err) +} + +// Unwrap returns the nested error causing the max attempts error. Provides the +// implementation for errors.Is and errors.As to unwrap nested errors. +func (e *MaxAttemptsError) Unwrap() error { + return e.Err +} + +// RequestCanceledError is the error that will be returned by an API request +// that was canceled. Requests given a Context may return this error when +// canceled. +type RequestCanceledError struct { + Err error +} + +// CanceledError returns true to satisfy interfaces checking for canceled errors. +func (*RequestCanceledError) CanceledError() bool { return true } + +// Unwrap returns the underlying error, if there was one. +func (e *RequestCanceledError) Unwrap() error { + return e.Err +} +func (e *RequestCanceledError) Error() string { + return fmt.Sprintf("request canceled, %v", e.Err) +} // A Request is the service request to be made. type Request struct { @@ -51,20 +114,26 @@ type Request struct { Error error Data interface{} RequestID string - RetryCount int - Retryable *bool - RetryDelay time.Duration NotHoist bool SignedHeaderVals http.Header LastSignedAt time.Time - context context.Context + // ID for this operation's request that is shared across attempts. + InvocationID string + + // The attempt number of this request for the operation. + AttemptNum int + // The number of times the operation has be retried. + RetryCount int - built bool + // Set by the request ShouldRetry handler to direct the request to retry + // the attempt. + ShouldRetry bool + // The backoff delay before retrying the request. + RetryDelay time.Duration - // Additional API error codes that should be retried. IsErrorRetryable - // will consider these codes in addition to its built in cases. - RetryErrorCodes []string + context context.Context + built bool // Additional API error codes that should be retried with throttle backoff // delay. IsErrorThrottle will consider these codes in addition to its @@ -95,9 +164,9 @@ type Operation struct { // Data is pointer value to an object which the request's response // payload will be deserialized to. func New(cfg Config, metadata Metadata, handlers Handlers, - retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request { + retryDecider Retryer, operation *Operation, params interface{}, data interface{}) *Request { - // TODO improve this experiance for config copy? + // TODO improve this experience for config copy? cfg = cfg.Copy() method := operation.HTTPMethod @@ -106,24 +175,34 @@ func New(cfg Config, metadata Metadata, handlers Handlers, } httpReq, _ := http.NewRequest(method, "", nil) - r := &Request{ Config: cfg, Metadata: metadata, Handlers: handlers.Copy(), - Retryer: retryer, + Retryer: retryDecider, Time: time.Now(), - ExpireTime: 0, Operation: operation, HTTPRequest: httpReq, - Body: nil, Params: params, Data: data, } r.SetBufferBody([]byte{}) - // TODO need better way of handling this error... NewRequest should return error. - endpoint, err := cfg.EndpointResolver.ResolveEndpoint(metadata.EndpointsID, cfg.Region) + if r.Retryer == nil { + r.Retryer = &NoOpRetryer{} + } + + // TODO need better way of handling this error... NewRequest should return + // error. + uuid, err := sdk.UUIDVersion4() + if err != nil { + r.Error = err + return r + } + r.InvocationID = uuid + + endpoint, err := cfg.EndpointResolver.ResolveEndpoint( + metadata.EndpointsID, cfg.Region) if err == nil { r.SetEndpoint(endpoint) @@ -217,14 +296,6 @@ func (r *Request) SetContext(ctx context.Context) { setRequestContext(ctx, r) } -// WillRetry returns if the request's can be retried. -func (r *Request) WillRetry() bool { - if !IsReaderSeekable(r.Body) && r.HTTPRequest.Body != http.NoBody { - return false - } - return r.Error != nil && BoolValue(r.Retryable) && r.RetryCount < r.Retryer.MaxRetries() -} - // fmtAttemptCount returns a formatted string with attempt count func fmtAttemptCount(retryCount, maxRetries int) string { return fmt.Sprintf("attempt %v/%v", retryCount, maxRetries) @@ -445,29 +516,57 @@ func (r *Request) Send() error { return err } + // TODO (jasdel), Issue #74 - Refactoring request error handling needs to + // consider the difference between API, connection, and SDK behavior + // errors. This consideration must include wrapping of underlying error + // when any SDK error occurs. + + relRetryToken := r.Retryer.GetInitialToken() for { r.Error = nil - r.AttemptTime = time.Now() + r.RetryDelay = 0 + r.ShouldRetry = false + r.AttemptTime = sdk.NowTime() + r.AttemptNum++ - if err := r.Sign(); err != nil { + var err error + if err = r.Sign(); err != nil { debugLogReqError(r, "Sign Request", notRetrying, err) + r.Error = err return err } - if err := r.sendRequest(); err == nil { + reqErr := r.sendRequest() + relRetryToken(reqErr) + if reqErr == nil { return nil } - r.Handlers.Retry.Run(r) - r.Handlers.AfterRetry.Run(r) + debugLogReqError(r, "Send Request", + fmtAttemptCount(r.AttemptNum, r.Retryer.MaxAttempts()), + reqErr) - if r.Error != nil || !BoolValue(r.Retryable) { + if !r.ShouldRetry { return r.Error } - if err := r.prepareRetry(); err != nil { + relRetryToken, err = r.Retryer.GetRetryToken(r.Context(), reqErr) + if err != nil { r.Error = err return err } + + if err = sdk.SleepWithContext(r.Context(), r.RetryDelay); err != nil { + r.Error = &RequestCanceledError{Err: err} + return r.Error + } + + r.Error = nil + if err = r.prepareRetry(); err != nil { + r.Error = err + return err + } + + r.RetryCount++ } } @@ -499,13 +598,14 @@ func (r *Request) prepareRetry() error { func (r *Request) sendRequest() (sendErr error) { defer r.Handlers.CompleteAttempt.Run(r) + defer func() { + if r.Error != nil { + r.Handlers.ShouldRetry.Run(r) + } + }() - r.Retryable = nil r.Handlers.Send.Run(r) if r.Error != nil { - debugLogReqError(r, "Send Request", - fmtAttemptCount(r.RetryCount, r.Retryer.MaxRetries()), - r.Error) return r.Error } @@ -513,17 +613,11 @@ func (r *Request) sendRequest() (sendErr error) { r.Handlers.ValidateResponse.Run(r) if r.Error != nil { r.Handlers.UnmarshalError.Run(r) - debugLogReqError(r, "Validate Response", - fmtAttemptCount(r.RetryCount, r.Retryer.MaxRetries()), - r.Error) return r.Error } r.Handlers.Unmarshal.Run(r) if r.Error != nil { - debugLogReqError(r, "Unmarshal Response", - fmtAttemptCount(r.RetryCount, r.Retryer.MaxRetries()), - r.Error) return r.Error } diff --git a/aws/request_pagination_test.go b/aws/request_pagination_test.go index e32bdd2f24b..e50ed8bd31c 100644 --- a/aws/request_pagination_test.go +++ b/aws/request_pagination_test.go @@ -7,6 +7,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/internal/awsutil" ) @@ -58,9 +59,7 @@ func TestPagination(t *testing.T) { }, } - retryer := aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 - }) + retryer := retry.NewStandard() op := aws.Operation{ Name: "Operation", Paginator: &aws.Paginator{ @@ -162,9 +161,7 @@ func TestPaginationTruncation(t *testing.T) { } reqNum := 0 - retryer := aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 - }) + retryer := retry.NewStandard() ops := []aws.Operation{ { Name: "Operation", @@ -275,9 +272,7 @@ func BenchmarkPagination(b *testing.B) { {aws.String("3"), aws.String("")}, } - retryer := aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 - }) + retryer := retry.NewStandard() op := aws.Operation{ Name: "Operation", Paginator: &aws.Paginator{ @@ -345,9 +340,7 @@ func TestPaginationWithContextCancel(t *testing.T) { }, } - retryer := aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 - }) + retryer := retry.NewStandard() op := aws.Operation{ Name: "Operation", Paginator: &aws.Paginator{ diff --git a/aws/request_retry_test.go b/aws/request_retry_test.go deleted file mode 100644 index ffeb6a52ba8..00000000000 --- a/aws/request_retry_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package aws - -import ( - "fmt" - "net" - "net/http" - "net/http/httptest" - "net/url" - "os" - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" -) - -func newRequest(t *testing.T, url string) *http.Request { - r, err := http.NewRequest("GET", url, nil) - if err != nil { - t.Fatalf("can't forge request: %v", err) - } - return r -} - -func TestShouldRetryError_nil(t *testing.T) { - if shouldRetryError(nil) != true { - t.Error("shouldRetryError(nil) should return true") - } -} - -func TestShouldRetryError_timeout(t *testing.T) { - - tr := &http.Transport{} - defer tr.CloseIdleConnections() - client := http.Client{ - Timeout: time.Nanosecond, - Transport: tr, - } - - resp, err := client.Do(newRequest(t, "https://179.179.179.179/no/such/host")) - if resp != nil { - resp.Body.Close() - } - if err == nil { - t.Fatal("This should have failed.") - } - debugerr(t, err) - - if shouldRetryError(err) == false { - t.Errorf("this request timed out and should be retried") - } -} - -func TestShouldRetryError_cancelled(t *testing.T) { - tr := &http.Transport{} - defer tr.CloseIdleConnections() - client := http.Client{ - Transport: tr, - } - - cancelWait := make(chan bool) - srvrWait := make(chan bool) - srvr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - close(cancelWait) // Trigger the request cancel. - time.Sleep(100 * time.Millisecond) - - fmt.Fprintf(w, "Hello") - w.(http.Flusher).Flush() // send headers and some body - <-srvrWait // block forever - })) - defer srvr.Close() - defer close(srvrWait) - - r := newRequest(t, srvr.URL) - ch := make(chan struct{}) - r.Cancel = ch - - // Ensure the request has started, and client has started to receive bytes. - // This ensures the test is stable and does not run into timing with the - // request being canceled, before or after the http request is made. - go func() { - <-cancelWait - close(ch) // request is cancelled before anything - }() - - resp, err := client.Do(r) - if resp != nil { - resp.Body.Close() - } - if err == nil { - t.Fatal("This should have failed.") - } - - debugerr(t, err) - - if shouldRetryError(err) == true { - t.Errorf("this request was cancelled and should not be retried") - } -} - -func TestShouldRetry(t *testing.T) { - - syscallError := os.SyscallError{ - Err: ErrInvalidParams{}, - Syscall: "open", - } - - opError := net.OpError{ - Op: "dial", - Net: "tcp", - Source: net.Addr(nil), - Err: &syscallError, - } - - urlError := url.Error{ - Op: "Post", - URL: "https://localhost:52398", - Err: &opError, - } - origError := awserr.New("ErrorTestShouldRetry", "Test should retry when error received", &urlError).OrigErr() - if e, a := true, shouldRetryError(origError); e != a { - t.Errorf("Expected to return %v to retry when error occured, got %v instead", e, a) - } - -} - -func debugerr(t *testing.T, err error) { - t.Logf("Error, %v", err) - - switch err := err.(type) { - case temporary: - t.Logf("%s is a temporary error: %t", err, err.Temporary()) - return - case *url.Error: - t.Logf("err: %s, nested err: %#v", err, err.Err) - if operr, ok := err.Err.(*net.OpError); ok { - t.Logf("operr: %#v", operr) - } - debugerr(t, err.Err) - return - default: - return - } -} - -func TestRequest_retryCustomCodes(t *testing.T) { - cases := map[string]struct { - Code string - RetryErrorCodes []string - ThrottleErrorCodes []string - Retryable bool - Throttle bool - }{ - "retry code": { - Code: "RetryMePlease", - RetryErrorCodes: []string{ - "RetryMePlease", - "SomeOtherError", - }, - Retryable: true, - }, - "throttle code": { - Code: "AThrottleableError", - RetryErrorCodes: []string{ - "RetryMePlease", - "SomeOtherError", - }, - ThrottleErrorCodes: []string{ - "AThrottleableError", - "SomeOtherError", - }, - Throttle: true, - }, - "unknown code": { - Code: "UnknownCode", - RetryErrorCodes: []string{ - "RetryMePlease", - "SomeOtherError", - }, - Retryable: false, - }, - } - - for name, c := range cases { - t.Run(name, func(t *testing.T) { - req := Request{ - HTTPRequest: &http.Request{}, - HTTPResponse: &http.Response{}, - Error: awserr.New(c.Code, "some error", nil), - RetryErrorCodes: c.RetryErrorCodes, - ThrottleErrorCodes: c.ThrottleErrorCodes, - } - - retryable := req.IsErrorRetryable() - if e, a := c.Retryable, retryable; e != a { - t.Errorf("%s, expect %v retryable, got %v", name, e, a) - } - - throttle := req.IsErrorThrottle() - if e, a := c.Throttle, throttle; e != a { - t.Errorf("%s, expect %v throttle, got %v", name, e, a) - } - }) - } -} diff --git a/aws/request_test.go b/aws/request_test.go index 9e8706dbb57..4d3f45e3ee1 100644 --- a/aws/request_test.go +++ b/aws/request_test.go @@ -20,6 +20,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -77,7 +78,7 @@ type jsonErrorResponse struct { // test that retries occur for 5xx status codes func TestRequestRecoverRetry5xx(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() reqNum := 0 @@ -88,8 +89,8 @@ func TestRequestRecoverRetry5xx(t *testing.T) { } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 10 }) s := awstesting.NewClient(cfg) @@ -117,20 +118,20 @@ func TestRequestRecoverRetry5xx(t *testing.T) { // test that retries occur for 4xx status codes with a response type that can be retried - see `shouldRetry` func TestRequestRecoverRetry4xxRetryable(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() reqNum := 0 reqs := []http.Response{ {StatusCode: 400, Body: body(`{"__type":"Throttling","message":"Rate exceeded."}`)}, {StatusCode: 400, Body: body(`{"__type":"ProvisionedThroughputExceededException","message":"Rate exceeded."}`)}, - {StatusCode: 429, Body: body(`{"__type":"FooException","message":"Rate exceeded."}`)}, + {StatusCode: 400, Body: body(`{"__type":"Throttling","message":"Rate exceeded."}`)}, {StatusCode: 200, Body: body(`{"data":"valid"}`)}, } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 10 }) s := awstesting.NewClient(cfg) @@ -159,8 +160,8 @@ func TestRequestRecoverRetry4xxRetryable(t *testing.T) { // test that retries don't occur for 4xx status codes with a response type that can't be retried func TestRequest4xxUnretryable(t *testing.T) { cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 1 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 1 }) s := awstesting.NewClient(cfg) @@ -197,7 +198,7 @@ func TestRequest4xxUnretryable(t *testing.T) { } func TestRequestExhaustRetries(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() orig := sdk.SleepWithContext @@ -232,133 +233,17 @@ func TestRequestExhaustRetries(t *testing.T) { if err == nil { t.Fatalf("expect error, but did not get one") } - aerr := err.(awserr.RequestFailure) - if e, a := 500, aerr.StatusCode(); e != a { - t.Errorf("expect %d status code, got %d", e, a) - } - if e, a := "UnknownError", aerr.Code(); e != a { - t.Errorf("expect %q error code, got %q", e, a) - } - if e, a := "An error occurred.", aerr.Message(); e != a { - t.Errorf("expect %q error message, got %q", e, a) - } - if e, a := 3, int(r.RetryCount); e != a { - t.Errorf("expect %d retry count, got %d", e, a) - } - - expectDelays := []struct{ min, max time.Duration }{{30, 60}, {60, 120}, {120, 240}} - for i, v := range delays { - min := expectDelays[i].min * time.Millisecond - max := expectDelays[i].max * time.Millisecond - if !(min <= v && v <= max) { - t.Errorf("expect delay to be within range, i:%d, v:%s, min:%s, max:%s", - i, v, min, max) - } - } -} - -// test that the request is retried after the credentials are expired. -func TestRequest_RecoverExpiredCreds(t *testing.T) { - reqNum := 0 - reqs := []http.Response{ - {StatusCode: 400, Body: body(`{"__type":"ExpiredTokenException","message":"expired token"}`)}, - {StatusCode: 200, Body: body(`{"data":"valid"}`)}, - } - expectCreds := []aws.Credentials{ - { - AccessKeyID: "expiredKey", - SecretAccessKey: "expiredSecret", - }, - { - AccessKeyID: "AKID", - SecretAccessKey: "SECRET", - }, - } - - cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 - }) - - credsInvalidated := false - credsProvider := func() aws.CredentialsProvider { - creds := expectCreds[0] - return awstesting.MockCredentialsProvider{ - RetrieveFn: func(ctx context.Context) (aws.Credentials, error) { - return creds, nil - }, - InvalidateFn: func() { - creds = expectCreds[1] - credsInvalidated = true - }, - } - }() - cfg.Credentials = credsProvider - - s := awstesting.NewClient(cfg) - - s.Handlers.Validate.Clear() - s.Handlers.Unmarshal.PushBack(unmarshal) - s.Handlers.UnmarshalError.PushBack(unmarshalError) - s.Handlers.Build.PushFront(func(r *aws.Request) { - creds, err := r.Config.Credentials.Retrieve(context.Background()) - if err != nil { - t.Fatalf("expect no error, got %v", err) - } - if e, a := "expiredKey", creds.AccessKeyID; e != a { - t.Errorf("expect %v key, got %v", e, a) - } - if e, a := "expiredSecret", creds.SecretAccessKey; e != a { - t.Errorf("expect %v secret, got %v", e, a) - } - }) - - s.Handlers.AfterRetry.PushBack(func(r *aws.Request) { - if !credsInvalidated { - t.Errorf("expect creds to be invalidated") - } - }) - - s.Handlers.Sign.Clear() - s.Handlers.Sign.PushBack(func(r *aws.Request) { - creds, err := r.Config.Credentials.Retrieve(context.Background()) - if err != nil { - t.Errorf("expect no error, got %v", err) - } - if e, a := expectCreds[reqNum].AccessKeyID, creds.AccessKeyID; e != a { - t.Errorf("expect %v key, got %v", e, a) - } - if e, a := expectCreds[reqNum].SecretAccessKey, creds.SecretAccessKey; e != a { - t.Errorf("expect %v secret, got %v", e, a) - } - }) - s.Handlers.Send.Clear() // mock sending - s.Handlers.Send.PushBack(func(r *aws.Request) { - r.HTTPResponse = &reqs[reqNum] - reqNum++ - }) - - out := &testData{} - r := s.NewRequest(&aws.Operation{Name: "Operation"}, nil, out) - err := r.Send() - if err != nil { - t.Fatalf("expect no error, got %v", err) - } - creds, err := r.Config.Credentials.Retrieve(context.Background()) - if err != nil { - t.Fatalf("expect no error, got %v", err) + var aerr awserr.RequestFailure + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) } - if creds.Expired() { - t.Errorf("expect valid creds after cred expired recovery") + if e, a := 500, aerr.StatusCode(); e != a { + t.Errorf("expect %d status code, got %d", e, a) } - - if e, a := 1, int(r.RetryCount); e != a { + if e, a := r.Retryer.MaxAttempts(), reqNum; e != a { t.Errorf("expect %d retry count, got %d", e, a) } - if e, a := "valid", out.Data; e != a { - t.Errorf("expect %q output got %q", e, a) - } } func TestMakeAddtoUserAgentHandler(t *testing.T) { @@ -412,7 +297,7 @@ func TestRequestThrottleRetries(t *testing.T) { return nil } - reqNum := 0 + var reqNum int reqs := []http.Response{ {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, @@ -435,7 +320,12 @@ func TestRequestThrottleRetries(t *testing.T) { if err == nil { t.Fatalf("expect error, but did not get one") } - aerr := err.(awserr.RequestFailure) + + var aerr awserr.RequestFailure + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) + } + if e, a := 500, aerr.StatusCode(); e != a { t.Errorf("expect %d status code, got %d", e, a) } @@ -445,24 +335,14 @@ func TestRequestThrottleRetries(t *testing.T) { if e, a := "An error occurred.", aerr.Message(); e != a { t.Errorf("expect %q error message, got %q", e, a) } - if e, a := 3, int(r.RetryCount); e != a { + if e, a := s.Retryer.MaxAttempts(), reqNum; e != a { t.Errorf("expect %d retry count, got %d", e, a) } - - expectDelays := []struct{ min, max time.Duration }{{500, 1000}, {1000, 2000}, {2000, 4000}} - for i, v := range delays { - min := expectDelays[i].min * time.Millisecond - max := expectDelays[i].max * time.Millisecond - if !(min <= v && v <= max) { - t.Errorf("expect delay to be within range, i:%d, v:%s, min:%s, max:%s", - i, v, min, max) - } - } } // test that retries occur for request timeouts when response.Body can be nil func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { - reqNum := 0 + var reqNum int reqs := []*http.Response{ {StatusCode: 0, Body: nil}, // body can be nil when requests time out {StatusCode: 200, Body: body(`{"data":"valid"}`)}, @@ -472,8 +352,8 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 10 }) s := awstesting.NewClient(cfg) @@ -481,12 +361,10 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { s.Handlers.Validate.Clear() s.Handlers.Unmarshal.PushBack(unmarshal) s.Handlers.UnmarshalError.PushBack(unmarshalError) - s.Handlers.AfterRetry.Clear() // force retry on all errors - s.Handlers.AfterRetry.PushBack(func(r *aws.Request) { + s.Handlers.ShouldRetry.Clear() + s.Handlers.ShouldRetry.PushFront(func(r *aws.Request) { if r.Error != nil { - r.Error = nil - r.Retryable = aws.Bool(true) - r.RetryCount++ + r.ShouldRetry = true } }) s.Handlers.Send.Clear() // mock sending @@ -495,13 +373,15 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { r.Error = errors[reqNum] reqNum++ }) + out := &testData{} r := s.NewRequest(&aws.Operation{Name: "Operation"}, nil, out) err := r.Send() if err != nil { t.Fatalf("expect no error, but got %v", err) } - if e, a := 1, int(r.RetryCount); e != a { + + if e, a := 2, reqNum; e != a { t.Errorf("expect %d retry count, got %d", e, a) } if e, a := "valid", out.Data; e != a { @@ -510,7 +390,7 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { } func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) { - reqNum := 0 + var reqNum int reqs := []*http.Response{ nil, {StatusCode: 200, Body: body(`{"data":"valid"}`)}, @@ -521,21 +401,18 @@ func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) { } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 10 }) s := awstesting.NewClient(cfg) - s.Handlers.Validate.Clear() s.Handlers.Unmarshal.PushBack(unmarshal) s.Handlers.UnmarshalError.PushBack(unmarshalError) - s.Handlers.AfterRetry.Clear() // force retry on all errors - s.Handlers.AfterRetry.PushBack(func(r *aws.Request) { + s.Handlers.ShouldRetry.Clear() + s.Handlers.ShouldRetry.PushFront(func(r *aws.Request) { if r.Error != nil { - r.Error = nil - r.Retryable = aws.Bool(true) - r.RetryCount++ + r.ShouldRetry = true } }) s.Handlers.Send.Clear() // mock sending @@ -550,7 +427,8 @@ func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) { if err != nil { t.Fatalf("expect no error, but got %v", err) } - if e, a := 1, int(r.RetryCount); e != a { + + if e, a := 2, reqNum; e != a { t.Errorf("expect %d retry count, got %d", e, a) } if e, a := "valid", out.Data; e != a { @@ -620,39 +498,6 @@ func TestRequest_NoBody(t *testing.T) { } } -func TestIsSerializationErrorRetryable(t *testing.T) { - testCases := []struct { - err error - expected bool - }{ - { - err: awserr.New(aws.ErrCodeSerialization, "foo error", nil), - expected: false, - }, - { - err: awserr.New("ErrFoo", "foo error", nil), - expected: false, - }, - { - err: nil, - expected: false, - }, - { - err: awserr.New(aws.ErrCodeSerialization, "foo error", stubConnectionResetError), - expected: true, - }, - } - - for i, c := range testCases { - r := &aws.Request{ - Error: c.err, - } - if r.IsErrorRetryable() != c.expected { - t.Errorf("Case %d: expected %v, but received %v", i, c.expected, !c.expected) - } - } -} - func TestWithLogLevel(t *testing.T) { r := &aws.Request{} @@ -714,11 +559,10 @@ func TestWithGetResponseHeaders(t *testing.T) { } } -type connResetCloser struct { -} +type connResetCloser struct{} func (rc *connResetCloser) Read(b []byte) (int, error) { - return 0, stubConnectionResetError + return 0, fmt.Errorf("connection reset") } func (rc *connResetCloser) Close() error { @@ -726,7 +570,7 @@ func (rc *connResetCloser) Close() error { } func TestSerializationErrConnectionReset(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() count := 0 @@ -742,7 +586,7 @@ func TestSerializationErrConnectionReset(t *testing.T) { handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) - handlers.AfterRetry.PushBackNamed(defaults.AfterRetryHandler) + handlers.ShouldRetry.PushBackNamed(defaults.RetryableCheckHandler) op := &aws.Operation{ Name: "op", @@ -759,94 +603,73 @@ func TestSerializationErrConnectionReset(t *testing.T) { TargetPrefix: "Foo", } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 5 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 5 }) req := aws.New( cfg, meta, handlers, - aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 5 - }), + cfg.Retryer, op, &struct{}{}, &struct{}{}, ) - osErr := stubConnectionResetError + expectNestedErr := fmt.Errorf("connection reset") req.ApplyOptions(aws.WithResponseReadTimeout(time.Second)) err := req.Send() if err == nil { - t.Error("expected rror 'SerializationError', but received nil") - } - if aerr, ok := err.(awserr.Error); ok && aerr.Code() != "SerializationError" { - t.Errorf("expected 'SerializationError', but received %q", aerr.Code()) - } else if !ok { - t.Errorf("expected 'awserr.Error', but received %v", reflect.TypeOf(err)) - } else if aerr.OrigErr().Error() != osErr.Error() { - t.Errorf("expected %q, but received %q", osErr.Error(), aerr.OrigErr().Error()) + t.Error("expect error, got none") } - if count != 6 { - t.Errorf("expected '6', but received %d", count) + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) + } + if e, a := aws.ErrCodeSerialization, aerr.Code(); e != a { + t.Errorf("expect %v code, got %v", e, a) } -} - -type testRetryer struct { - shouldRetry bool -} - -func (d *testRetryer) MaxRetries() int { - return 3 -} - -// RetryRules returns the delay duration before retrying this request again -func (d *testRetryer) RetryRules(r *aws.Request) time.Duration { - return time.Duration(time.Millisecond) -} -func (d *testRetryer) ShouldRetry(r *aws.Request) bool { - d.shouldRetry = true - if r.Retryable != nil { - return *r.Retryable + nested := errors.Unwrap(aerr) + if nested == nil { + t.Fatalf("expect nested error, got none") + } + if e, a := expectNestedErr.Error(), nested.Error(); e != a { + t.Errorf("expect %v nested error, got %v", e, a) } - if r.HTTPResponse.StatusCode >= 500 { - return true + if e, a := req.Retryer.MaxAttempts(), count; e != a { + t.Errorf("expect %v attempts, got %v", e, a) } - return r.IsErrorRetryable() } -func TestEnforceShouldRetryCheck(t *testing.T) { - restoreSleep := mockSleep() +func TestEnforceShouldRetry(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() - tp := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - ResponseHeaderTimeout: 1 * time.Millisecond, - } - - client := &http.Client{Transport: tp} - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // This server should wait forever. Requests will timeout and the SDK should - // attempt to retry. - select {} - })) - - retryer := &testRetryer{} - cfg := unit.Config() cfg.Region = "mock-region" - cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL) - cfg.Retryer = retryer - cfg.HTTPClient = client + var attempts int s := awstesting.NewClient(cfg) - s.Handlers.Validate.Clear() + s.Handlers.Send.Clear() + s.Handlers.Send.PushBack(func(r *aws.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: 400, + Header: http.Header{}, + Body: ioutil.NopCloser(&bytes.Buffer{}), + } + attempts++ + }) + s.Handlers.ShouldRetry.PushBack(func(r *aws.Request) { + if attempts < 5 { + // Force retryable to true overriding the built in retryable check. + r.ShouldRetry = true + } + }) s.Handlers.Unmarshal.PushBack(unmarshal) s.Handlers.UnmarshalError.PushBack(unmarshalError) @@ -856,12 +679,9 @@ func TestEnforceShouldRetryCheck(t *testing.T) { if err == nil { t.Fatalf("expect error, but got nil") } - if e, a := 3, int(r.RetryCount); e != a { + if e, a := 5, attempts; e != a { t.Errorf("expect %d retry count, got %d", e, a) } - if !retryer.shouldRetry { - t.Errorf("expect 'true' for ShouldRetry, but got %v", retryer.shouldRetry) - } } type errReader struct { @@ -895,7 +715,7 @@ func TestIsNoBodyReader(t *testing.T) { } func TestRequest_TemporaryRetry(t *testing.T) { - restoreSleep := mockSleep() + restoreSleep := sdk.TestingUseNoOpSleep() defer restoreSleep() done := make(chan struct{}) @@ -913,8 +733,8 @@ func TestRequest_TemporaryRetry(t *testing.T) { defer server.Close() cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 1 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 2 }) cfg.HTTPClient = &http.Client{ Timeout: 100 * time.Millisecond, @@ -939,23 +759,23 @@ func TestRequest_TemporaryRetry(t *testing.T) { } close(done) - aerr := err.(awserr.Error) + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) + } if e, a := aws.ErrCodeSerialization, aerr.Code(); e != a { t.Errorf("expect %q error code, got %q", e, a) } - if e, a := 1, req.RetryCount; e != a { + if e, a := 2, req.AttemptNum; e != a { t.Errorf("expect %d retries, got %d", e, a) } - type temporary interface { - Temporary() bool + var terr interface{ Temporary() bool } + if !errors.As(aerr, &terr) { + t.Fatalf("expect %T error, got %v", terr, aerr) } - terr, ok := aerr.OrigErr().(temporary) - if !ok { - t.Fatalf("expect error to implement temporary, got %T", aerr.OrigErr()) - } if !terr.Temporary() { t.Errorf("expect temporary error, was not") } @@ -1014,8 +834,8 @@ func Test501NotRetrying(t *testing.T) { } cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 10 }) s := awstesting.NewClient(cfg) s.Handlers.Validate.Clear() @@ -1050,7 +870,7 @@ func TestRequestInvalidEndpoint(t *testing.T) { cfg, aws.Metadata{}, cfg.Handlers, - aws.NewDefaultRetryer(), + retry.NewStandard(), &aws.Operation{}, nil, nil, diff --git a/aws/retry/jitter_backoff.go b/aws/retry/jitter_backoff.go new file mode 100644 index 00000000000..c266996dea2 --- /dev/null +++ b/aws/retry/jitter_backoff.go @@ -0,0 +1,49 @@ +package retry + +import ( + "math" + "time" + + "github.com/aws/aws-sdk-go-v2/internal/rand" + "github.com/aws/aws-sdk-go-v2/internal/timeconv" +) + +// ExponentialJitterBackoff provides backoff delays with jitter based on the +// number of attempts. +type ExponentialJitterBackoff struct { + maxBackoff time.Duration + // precomputed number of attempts needed to reach max backoff. + maxBackoffAttempts float64 + + randFloat64 func() (float64, error) +} + +// NewExponentialJitterBackoff returns an ExponentialJitterBackoff configured +// for the max backoff. +func NewExponentialJitterBackoff(maxBackoff time.Duration) *ExponentialJitterBackoff { + return &ExponentialJitterBackoff{ + maxBackoff: maxBackoff, + maxBackoffAttempts: math.Log2( + float64(maxBackoff) / float64(time.Second)), + randFloat64: rand.CryptoRandFloat64, + } +} + +// BackoffDelay returns the duration to wait before the next attempt should be +// made. Returns an error if unable get a duration. +func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) { + if attempt > int(j.maxBackoffAttempts) { + return j.maxBackoff, nil + } + + b, err := j.randFloat64() + if err != nil { + return 0, err + } + + // [0.0, 1.0) * 2 ^ attempts + ri := int64(1 << uint64(attempt)) + delaySeconds := b * float64(ri) + + return timeconv.FloatSecondsDur(delaySeconds), nil +} diff --git a/aws/retry/jitter_backoff_test.go b/aws/retry/jitter_backoff_test.go new file mode 100644 index 00000000000..10951b32840 --- /dev/null +++ b/aws/retry/jitter_backoff_test.go @@ -0,0 +1,61 @@ +package retry + +import ( + "math" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/internal/timeconv" +) + +func TestExponentialJitterBackoff_AttemptDelay(t *testing.T) { + maxB := 1 - 1/float64(1<<53) + + cases := map[string]struct { + MaxBackoff time.Duration + RandFloat func() (float64, error) + Attempt int + Expect time.Duration + }{ + "min delay floor": { + MaxBackoff: 20 * time.Second, + RandFloat: func() (float64, error) { return 0, nil }, + Attempt: 1, + Expect: 0, + }, + "min delay ceiling": { + MaxBackoff: 20 * time.Second, + RandFloat: func() (float64, error) { return maxB, nil }, + Attempt: 1, + Expect: timeconv.FloatSecondsDur(maxB * float64(2)), + }, + "attempt delay": { + MaxBackoff: 20 * time.Second, + RandFloat: func() (float64, error) { return 0.5, nil }, + Attempt: 2, + Expect: timeconv.FloatSecondsDur(0.5 * float64(1<<2)), + }, + "max delay": { + MaxBackoff: 20 * time.Second, + RandFloat: func() (float64, error) { return maxB, nil }, + Attempt: 1 << 53, + Expect: timeconv.FloatSecondsDur(maxB * math.Exp2(math.Log2(20))), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + j := NewExponentialJitterBackoff(c.MaxBackoff) + j.randFloat64 = c.RandFloat + + d, err := j.BackoffDelay(c.Attempt, nil) + if err != nil { + t.Fatalf("expect not error, %v", err) + } + + if e, a := c.Expect, d; e != a { + t.Errorf("expect %v delay, got %v", e, a) + } + }) + } +} diff --git a/aws/retry/retry.go b/aws/retry/retry.go new file mode 100644 index 00000000000..9d8fc51aa81 --- /dev/null +++ b/aws/retry/retry.go @@ -0,0 +1,99 @@ +package retry + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" +) + +// Retryer defines an interface for extension utilities to extend the built in +// retryer. +type Retryer interface { + // IsErrorRetryable returns if the failed request is retryable. This check + // should determine if the error can be retried, or if the error is + // terminal. + IsErrorRetryable(error) bool + + // MaxAttempts returns the maximum number of attempts that can be made for + // a request before failing. A value of 0 implies that the request should + // be retried until it succeeds if the errors are retryable. + MaxAttempts() int + + // RetryDelay returns the delay that should be used before retrying the + // request. Will return error if the if the delay could not be determined. + RetryDelay(attempt int, opErr error) (time.Duration, error) + + // GetRetryToken attempts to deduct the retry cost from the retry token pool. + // Returning the token release function, or error. + GetRetryToken(ctx context.Context, opErr error) (releaseToken func(error) error, err error) + + // GetInitalToken returns the initial request token that can increment the + // retry token pool if the request is successful. + GetInitialToken() (releaseToken func(error) error) +} + +// AddWithErrorCodes returns a Retryer with additional error codes considered +// for determining if the error should be retried. +func AddWithErrorCodes(r Retryer, codes ...string) Retryer { + retryable := &RetryableErrorCode{ + Codes: map[string]struct{}{}, + } + for _, c := range codes { + retryable.Codes[c] = struct{}{} + } + + return &withIsErrorRetryable{ + Retryer: r, + Retryable: retryable, + } +} + +type withIsErrorRetryable struct { + Retryer + Retryable IsErrorRetryable +} + +func (r *withIsErrorRetryable) IsErrorRetryable(err error) bool { + if v := r.Retryable.IsErrorRetryable(err); v != aws.UnknownTernary { + return v.Bool() + } + return r.Retryer.IsErrorRetryable(err) +} + +// AddWithMaxAttempts returns a Retryer with MaxAttempts set to the value +// specified. +func AddWithMaxAttempts(r Retryer, max int) Retryer { + return &withMaxAttempts{ + Retryer: r, + Max: max, + } +} + +type withMaxAttempts struct { + Retryer + Max int +} + +func (w *withMaxAttempts) MaxAttempts() int { + return w.Max +} + +// AddWithMaxBackoffDelay returns a retryer wrapping the passed in retryer +// overriding the RetryDelay behavior for a alternate minimum initial backoff +// delay. +func AddWithMaxBackoffDelay(r Retryer, delay time.Duration) Retryer { + return &withMinBackoffDelay{ + Retryer: r, + backoff: NewExponentialJitterBackoff(delay), + } +} + +type withMinBackoffDelay struct { + Retryer + backoff *ExponentialJitterBackoff +} + +func (r *withMinBackoffDelay) RetryDelay(attempt int, err error) (time.Duration, error) { + return r.backoff.BackoffDelay(attempt, err) +} diff --git a/aws/retry/retry_test.go b/aws/retry/retry_test.go new file mode 100644 index 00000000000..feed5372f46 --- /dev/null +++ b/aws/retry/retry_test.go @@ -0,0 +1,35 @@ +package retry_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" +) + +func TestAddWithErrorCodes(t *testing.T) { + cases := map[string]struct { + Err error + Expect bool + }{ + "retryable": { + Err: awserr.New("Error1", "err", nil), + Expect: true, + }, + "not retryable": { + Err: awserr.New("Error3", "err", nil), + Expect: false, + }, + } + + r := retry.AddWithErrorCodes(aws.NoOpRetryer{}, "Error1", "Error2") + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.Expect, r.IsErrorRetryable(c.Err); e != a { + t.Errorf("expect %v, got %v", e, a) + } + }) + } +} diff --git a/aws/retry/retryable_error.go b/aws/retry/retryable_error.go new file mode 100644 index 00000000000..1458eb15d43 --- /dev/null +++ b/aws/retry/retryable_error.go @@ -0,0 +1,186 @@ +package retry + +import ( + "errors" + "net" + "net/url" + "strings" + + "github.com/aws/aws-sdk-go-v2/aws" +) + +// IsErrorRetryable provides the interface of an implementation to determine if +// a error as the result of an operation is retryable. +type IsErrorRetryable interface { + IsErrorRetryable(error) aws.Ternary +} + +// IsErrorRetryables is a collection of checks to determine of the error is +// retryable. Iterates through the checks and returns the state of retryable +// if any check returns something other than unknown. +type IsErrorRetryables []IsErrorRetryable + +// IsErrorRetryable returns if the error is retryable if any of the checks in +// the list return a value other than unknown. +func (r IsErrorRetryables) IsErrorRetryable(err error) aws.Ternary { + for _, re := range r { + if v := re.IsErrorRetryable(err); v != aws.UnknownTernary { + return v + } + } + return aws.UnknownTernary +} + +// IsErrorRetryableFunc wraps a function with the IsErrorRetryable interface. +type IsErrorRetryableFunc func(error) aws.Ternary + +// IsErrorRetryable returns if the error is retryable. +func (fn IsErrorRetryableFunc) IsErrorRetryable(err error) aws.Ternary { + return fn(err) +} + +// RetryableError is an IsErrorRetryable implementation which uses the +// optional interface Retryable on the error value to determine if the error is +// retryable. +type RetryableError struct{} + +// IsErrorRetryable returns if the error is retryable if it satisfies the +// Retryable interface, and returns if the attempt should be retried. +func (RetryableError) IsErrorRetryable(err error) aws.Ternary { + var v interface{ RetryableError() bool } + + if !errors.As(err, &v) { + return aws.UnknownTernary + } + + return aws.BoolTernary(v.RetryableError()) +} + +// NoRetryCanceledError detects if the error was an request canceled error and +// returns if so. +type NoRetryCanceledError struct{} + +// IsErrorRetryable returns the error is not retryable if the request was +// canceled. +func (NoRetryCanceledError) IsErrorRetryable(err error) aws.Ternary { + var v interface{ CanceledError() bool } + + if !errors.As(err, &v) { + return aws.UnknownTernary + } + + if v.CanceledError() { + return aws.FalseTernary + } + return aws.UnknownTernary +} + +// RetryableConnectionError determines if the underlying error is an HTTP +// connection and returns if it should be retried. +// +// Includes errors such as connection reset, connection refused, net dial, +// temporary, and timeout errors. +type RetryableConnectionError struct{} + +// IsErrorRetryable returns if the error is caused by and HTTP connection +// error, and should be retried. +func (r RetryableConnectionError) IsErrorRetryable(err error) aws.Ternary { + if err == nil { + return aws.UnknownTernary + } + var retryable bool + + var conErr interface{ ConnectionError() bool } + var tempErr interface{ Temporary() bool } + var timeoutErr interface{ Timeout() bool } + var urlErr *url.Error + var netOpErr *net.OpError + + switch { + case errors.As(err, &conErr) && conErr.ConnectionError(): + retryable = true + + case strings.Contains(err.Error(), "connection reset"): + retryable = true + + case errors.As(err, &urlErr): + // Refused connections should be retried as the service may not yet be + // running on the port. Go TCP dial considers refused connections as + // not temporary. + if strings.Contains(urlErr.Error(), "connection refused") { + retryable = true + } else { + return r.IsErrorRetryable(errors.Unwrap(urlErr)) + } + + case errors.As(err, &netOpErr): + // Network dial, or temporary network errors are always retryable. + if strings.EqualFold(netOpErr.Op, "dial") || netOpErr.Temporary() { + retryable = true + } else { + return r.IsErrorRetryable(errors.Unwrap(netOpErr)) + } + + case errors.As(err, &tempErr) && tempErr.Temporary(): + // Fallback to the generic temporary check, with temporary errors + // retryable. + retryable = true + + case errors.As(err, &timeoutErr) && timeoutErr.Timeout(): + // Fallback to the generic timeout check, with timeout errors + // retryable. + retryable = true + + default: + return aws.UnknownTernary + } + + return aws.BoolTernary(retryable) + +} + +// RetryableHTTPStatusCode provides a IsErrorRetryable based on HTTP status +// codes. +type RetryableHTTPStatusCode struct { + Codes map[int]struct{} +} + +// IsErrorRetryable return if the passed in error is retryable based on the +// HTTP status code. +func (r RetryableHTTPStatusCode) IsErrorRetryable(err error) aws.Ternary { + var v interface{ StatusCode() int } + + if !errors.As(err, &v) { + return aws.UnknownTernary + } + + _, ok := r.Codes[v.StatusCode()] + if !ok { + return aws.UnknownTernary + } + + return aws.TrueTernary +} + +// RetryableErrorCode determines if an attempt should be retried based on the +// API error code. +type RetryableErrorCode struct { + Codes map[string]struct{} +} + +// IsErrorRetryable return if the error is retryable based on the error codes. +// Returns unknown if the error doesn't have a code or it is unknown. +func (r RetryableErrorCode) IsErrorRetryable(err error) aws.Ternary { + var v interface{ Code() string } + + if !errors.As(err, &v) { + return aws.UnknownTernary + } + + _, ok := r.Codes[v.Code()] + if !ok { + return aws.UnknownTernary + } + + return aws.TrueTernary +} diff --git a/aws/retry/retryable_error_test.go b/aws/retry/retryable_error_test.go new file mode 100644 index 00000000000..15787128705 --- /dev/null +++ b/aws/retry/retryable_error_test.go @@ -0,0 +1,250 @@ +package retry_test + +import ( + "fmt" + "net" + "net/http" + "net/url" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" +) + +type mockTemporaryError struct{ b bool } + +func (m mockTemporaryError) Temporary() bool { return m.b } +func (m mockTemporaryError) Error() string { + return fmt.Sprintf("mock temporary %t", m.b) +} + +type mockTimeoutError struct{ b bool } + +func (m mockTimeoutError) Timeout() bool { return m.b } +func (m mockTimeoutError) Error() string { + return fmt.Sprintf("mock timeout %t", m.b) +} + +type mockRetryableError struct{ b bool } + +func (m mockRetryableError) RetryableError() bool { return m.b } +func (m mockRetryableError) Error() string { + return fmt.Sprintf("mock retryable %t", m.b) +} + +type mockCanceledError struct{ b bool } + +func (m mockCanceledError) CanceledError() bool { return m.b } +func (m mockCanceledError) Error() string { + return fmt.Sprintf("mock canceled %t", m.b) +} + +type mockStatusCodeError struct{ code int } + +func (m mockStatusCodeError) StatusCode() int { return m.code } +func (m mockStatusCodeError) Error() string { + return fmt.Sprintf("status code error, %v", m.code) +} + +func TestRetryConnectionErrors(t *testing.T) { + cases := map[string]struct { + Err error + Retryable aws.Ternary + }{ + "nested connection reset": { + Retryable: aws.TrueTernary, + Err: fmt.Errorf("serialization error, %w", + fmt.Errorf("connection reset")), + }, + "top level connection reset": { + Retryable: aws.TrueTernary, + Err: fmt.Errorf("connection reset"), + }, + "awserr connection reset": { + Retryable: aws.TrueTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + fmt.Errorf("connection reset")), + }, + "url.Error connection refused": { + Retryable: aws.TrueTernary, + Err: fmt.Errorf("some error, %w", &url.Error{ + Err: fmt.Errorf("connection refused"), + }), + }, + "other connection refused": { + Retryable: aws.UnknownTernary, + Err: fmt.Errorf("connection refused"), + }, + "nil error connection reset": { + Retryable: aws.UnknownTernary, + }, + "some other error": { + Retryable: aws.UnknownTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + fmt.Errorf("something bad")), + }, + "request send error": { + Retryable: aws.TrueTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + &aws.RequestSendError{Err: &url.Error{ + Err: fmt.Errorf("another error"), + }}), + }, + "temporary error": { + Retryable: aws.TrueTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + mockTemporaryError{b: true}, + ), + }, + "timeout error": { + Retryable: aws.TrueTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + mockTimeoutError{b: true}, + ), + }, + "timeout false error": { + Retryable: aws.UnknownTernary, + Err: awserr.New(aws.ErrCodeSerialization, "some error", + mockTimeoutError{b: false}, + ), + }, + "net.OpError dial": { + Retryable: aws.TrueTernary, + Err: &net.OpError{ + Op: "dial", + Err: mockTimeoutError{b: false}, + }, + }, + "net.OpError nested": { + Retryable: aws.TrueTernary, + Err: &net.OpError{ + Op: "read", + Err: fmt.Errorf("some error %w", mockTimeoutError{b: true}), + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + var r retry.RetryableConnectionError + + retryable := r.IsErrorRetryable(c.Err) + if e, a := c.Retryable, retryable; e != a { + t.Errorf("expect %v retryable, got %v", e, a) + } + }) + } +} + +func TestRetryHTTPStatusCodes(t *testing.T) { + cases := map[string]struct { + Err error + Expect aws.Ternary + }{ + "top level": { + Err: &mockStatusCodeError{code: 500}, + Expect: aws.TrueTernary, + }, + "nested": { + Err: fmt.Errorf("some error, %w", &mockStatusCodeError{code: 500}), + Expect: aws.TrueTernary, + }, + "response error": { + Err: fmt.Errorf("some error, %w", &aws.HTTPResponseError{ + Response: &http.Response{StatusCode: 502}, + }), + Expect: aws.TrueTernary, + }, + } + + r := retry.RetryableHTTPStatusCode{Codes: map[int]struct{}{ + 500: struct{}{}, + 502: struct{}{}, + }} + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.Expect, r.IsErrorRetryable(c.Err); e != a { + t.Errorf("expect %v, got %v", e, a) + } + }) + } +} + +func TestRetryErrorCodes(t *testing.T) { + cases := map[string]struct { + Err error + Expect aws.Ternary + }{ + "retryable code": { + Err: &aws.MaxAttemptsError{ + Err: awserr.New("ErrorCode1", "some error", nil), + }, + Expect: aws.TrueTernary, + }, + "not retryable code": { + Err: &aws.MaxAttemptsError{ + Err: awserr.New("SomeErroCode", "some error", nil), + }, + Expect: aws.UnknownTernary, + }, + "other error": { + Err: fmt.Errorf("some other error"), + Expect: aws.UnknownTernary, + }, + } + + r := retry.RetryableErrorCode{Codes: map[string]struct{}{ + "ErrorCode1": struct{}{}, + "ErrorCode2": struct{}{}, + }} + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.Expect, r.IsErrorRetryable(c.Err); e != a { + t.Errorf("expect %v, got %v", e, a) + } + }) + } +} + +func TestCanceledError(t *testing.T) { + cases := map[string]struct { + Err error + Expect aws.Ternary + }{ + "canceled error": { + Err: fmt.Errorf("some error, %w", &aws.RequestCanceledError{ + Err: fmt.Errorf(":("), + }), + Expect: aws.FalseTernary, + }, + "canceled retryable error": { + Err: fmt.Errorf("some error, %w", &aws.RequestCanceledError{ + Err: mockRetryableError{b: true}, + }), + Expect: aws.FalseTernary, + }, + "not canceled error": { + Err: fmt.Errorf("some error, %w", mockCanceledError{b: false}), + Expect: aws.UnknownTernary, + }, + "retryable error": { + Err: fmt.Errorf("some error, %w", mockRetryableError{b: true}), + Expect: aws.TrueTernary, + }, + } + + r := retry.IsErrorRetryables{ + retry.NoRetryCanceledError{}, + retry.RetryableError{}, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.Expect, r.IsErrorRetryable(c.Err); e != a { + t.Errorf("Expect %v retryable, got %v", e, a) + } + }) + } +} diff --git a/aws/retry/standard.go b/aws/retry/standard.go new file mode 100644 index 00000000000..3484d79af06 --- /dev/null +++ b/aws/retry/standard.go @@ -0,0 +1,210 @@ +package retry + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go-v2/aws/ratelimit" +) + +// BackoffDelayer provides the interface for determining the delay to before +// another request attempt, that previously failed. +type BackoffDelayer interface { + BackoffDelay(attempt int, err error) (time.Duration, error) +} + +// BackoffDelayerFunc provides a wrapper around a function to determine the +// backoff delay of an attempt retry. +type BackoffDelayerFunc func(int, error) (time.Duration, error) + +// BackoffDelay returns the delay before attempt to retry a request. +func (fn BackoffDelayerFunc) BackoffDelay(attempt int, err error) (time.Duration, error) { + return fn(attempt, err) +} + +const ( + // DefaultMaxAttempts is the maximum of attempts for an API request + DefaultMaxAttempts int = 3 + + // DefaultMaxBackoff is the maximum back off delay between attempts + DefaultMaxBackoff time.Duration = 20 * time.Second +) + +// Default retry token quota values. +const ( + DefaultRetryRateTokens uint = 500 + DefaultRetryCost uint = 5 + DefaultRetryTimeoutCost uint = 10 + DefaultNoRetryIncrement uint = 1 +) + +// DefaultRetryableHTTPStatusCodes is the default set of HTTP status codes the SDK +// should consider as retryable errors. +var DefaultRetryableHTTPStatusCodes = map[int]struct{}{ + 500: struct{}{}, + 502: struct{}{}, + 503: struct{}{}, + 504: struct{}{}, +} + +// DefaultRetryableErrorCodes provides the set of API error codes that should +// be retried. +var DefaultRetryableErrorCodes = map[string]struct{}{ + "RequestTimeout": struct{}{}, + "RequestTimeoutException": struct{}{}, + + // Throttled status codes + "Throttling": struct{}{}, + "ThrottlingException": struct{}{}, + "ThrottledException": struct{}{}, + "RequestThrottledException": struct{}{}, + "TooManyRequestsException": struct{}{}, + "ProvisionedThroughputExceededException": struct{}{}, + "TransactionInProgressException": struct{}{}, + "RequestLimitExceeded": struct{}{}, + "BandwidthLimitExceeded": struct{}{}, + "LimitExceededException": struct{}{}, + "RequestThrottled": struct{}{}, + "SlowDown": struct{}{}, + "PriorRequestNotComplete": struct{}{}, + "EC2ThrottledException": struct{}{}, +} + +// DefaultRetryables provides the set of retryable checks that are used by +// default. +var DefaultRetryables = []IsErrorRetryable{ + NoRetryCanceledError{}, + RetryableError{}, + RetryableConnectionError{}, + RetryableHTTPStatusCode{ + Codes: DefaultRetryableHTTPStatusCodes, + }, + RetryableErrorCode{ + Codes: DefaultRetryableErrorCodes, + }, +} + +// StandardOptions provides the functional options for configuring the standard +// retryable, and delay behavior. +type StandardOptions struct { + MaxAttempts int + MaxBackoff time.Duration + Backoff BackoffDelayer + + Retryables []IsErrorRetryable + Timeouts []IsErrorTimeout + + RateLimiter RateLimiter + RetryCost uint + RetryTimeoutCost uint + NoRetryIncrement uint +} + +// RateLimiter provides the interface for limiting the rate of request retries +// allowed by the retrier. +type RateLimiter interface { + GetToken(ctx context.Context, cost uint) (releaseToken func() error, err error) + AddTokens(uint) error +} + +func nopTokenRelease(error) error { return nil } + +// Standard is the standard retry pattern for the SDK. It uses a set of +// retryable checks to determine of the failed request should be retried, and +// what retry delay should be used. +type Standard struct { + options StandardOptions + + timeout IsErrorTimeout + retryable IsErrorRetryable + backoff BackoffDelayer +} + +// NewStandard initializes a standard retry behavior with defaults that can be +// overridden via functional options. +func NewStandard(fnOpts ...func(*StandardOptions)) *Standard { + o := StandardOptions{ + MaxAttempts: DefaultMaxAttempts, + MaxBackoff: DefaultMaxBackoff, + Retryables: DefaultRetryables, + + RateLimiter: ratelimit.NewTokenRateLimit(DefaultRetryRateTokens), + RetryCost: DefaultRetryCost, + RetryTimeoutCost: DefaultRetryTimeoutCost, + NoRetryIncrement: DefaultNoRetryIncrement, + } + for _, fn := range fnOpts { + fn(&o) + } + + backoff := o.Backoff + if backoff == nil { + backoff = NewExponentialJitterBackoff(o.MaxBackoff) + } + + rs := make([]IsErrorRetryable, len(o.Retryables)) + copy(rs, o.Retryables) + + ts := make([]IsErrorTimeout, len(o.Timeouts)) + copy(ts, o.Timeouts) + + return &Standard{ + options: o, + backoff: backoff, + retryable: IsErrorRetryables(rs), + timeout: IsErrorTimeouts(ts), + } +} + +// MaxAttempts returns the maximum number of attempts that can be made for a +// request before failing. +func (s *Standard) MaxAttempts() int { + return s.options.MaxAttempts +} + +// IsErrorRetryable returns if the error is can be retried or not. Should not +// consider the number of attempts made. +func (s *Standard) IsErrorRetryable(err error) bool { + return s.retryable.IsErrorRetryable(err).Bool() +} + +// RetryDelay returns the delay to use before another request attempt is made. +func (s *Standard) RetryDelay(attempt int, err error) (time.Duration, error) { + return s.backoff.BackoffDelay(attempt, err) +} + +// GetInitialToken returns the initial request token that can increment the +// retry token pool if the request is successful. +func (s *Standard) GetInitialToken() func(error) error { + return releaseToken(s.incrementTokens).release +} + +func (s *Standard) incrementTokens() error { + return s.options.RateLimiter.AddTokens(s.options.NoRetryIncrement) +} + +// GetRetryToken attempts to deduct the retry cost from the retry token pool. +// Returning the token release function, or error. +func (s *Standard) GetRetryToken(ctx context.Context, err error) (func(error) error, error) { + cost := s.options.RetryCost + if s.timeout.IsErrorTimeout(err).Bool() { + cost = s.options.RetryTimeoutCost + } + + fn, err := s.options.RateLimiter.GetToken(ctx, cost) + if err != nil { + return nil, err + } + + return releaseToken(fn).release, nil +} + +type releaseToken func() error + +func (f releaseToken) release(err error) error { + if err != nil { + return nil + } + + return f() +} diff --git a/aws/retry/standard_test.go b/aws/retry/standard_test.go new file mode 100644 index 00000000000..cc152490680 --- /dev/null +++ b/aws/retry/standard_test.go @@ -0,0 +1,158 @@ +package retry_test + +import ( + "fmt" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" +) + +var _ aws.Retryer = (*retry.Standard)(nil) + +func TestStandard_IsErrorRetryable(t *testing.T) { + cases := map[string]struct { + Retryable retry.IsErrorRetryable + Err error + Expect bool + }{ + "is retryable": { + Expect: true, + Err: fmt.Errorf("expected error"), + Retryable: retry.IsErrorRetryableFunc( + func(error) aws.Ternary { + return aws.TrueTernary + }), + }, + "is not retryable": { + Expect: false, + Err: fmt.Errorf("expected error"), + Retryable: retry.IsErrorRetryableFunc( + func(error) aws.Ternary { + return aws.FalseTernary + }), + }, + "unknown retryable": { + Expect: false, + Err: fmt.Errorf("expected error"), + Retryable: retry.IsErrorRetryableFunc( + func(error) aws.Ternary { + return aws.UnknownTernary + }), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + r := retry.NewStandard(func(o *retry.StandardOptions) { + o.Retryables = []retry.IsErrorRetryable{ + retry.IsErrorRetryableFunc( + func(err error) aws.Ternary { + if e, a := c.Err, err; e != a { + t.Fatalf("expect %v, error, got %v", e, a) + } + return c.Retryable.IsErrorRetryable(err) + }), + } + }) + if e, a := c.Expect, r.IsErrorRetryable(c.Err); e != a { + t.Errorf("expect %t retryable, got %t", e, a) + } + }) + } +} + +func TestStandard_MaxAttempts(t *testing.T) { + cases := map[string]struct { + Max int + Expect int + }{ + "defaults": { + Expect: 3, + }, + "custom": { + Max: 10, + Expect: 10, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + r := retry.NewStandard(func(o *retry.StandardOptions) { + if c.Max != 0 { + o.MaxAttempts = c.Max + } else { + c.Max = o.MaxAttempts + } + }) + if e, a := c.Max, r.MaxAttempts(); e != a { + t.Errorf("expect %v max, got %v", e, a) + } + }) + } +} + +func TestStandard_RetryDelay(t *testing.T) { + cases := map[string]struct { + Backoff retry.BackoffDelayer + Attempt int + Err error + Assert func(*testing.T, time.Duration, error) + ExpectDelay time.Duration + ExpectErr error + }{ + "success": { + Attempt: 2, + Err: fmt.Errorf("expected error"), + ExpectDelay: 10 * time.Millisecond, + + Backoff: retry.BackoffDelayerFunc( + func(attempt int, err error) (time.Duration, error) { + return 10 * time.Millisecond, nil + }), + }, + "error": { + Attempt: 2, + Err: fmt.Errorf("expected error"), + ExpectDelay: 0, + ExpectErr: fmt.Errorf("failed get delay"), + Backoff: retry.BackoffDelayerFunc( + func(attempt int, err error) (time.Duration, error) { + return 0, fmt.Errorf("failed get delay") + }), + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + r := retry.NewStandard(func(o *retry.StandardOptions) { + o.Backoff = retry.BackoffDelayerFunc( + func(attempt int, err error) (time.Duration, error) { + if e, a := c.Err, err; e != a { + t.Errorf("expect %v error, got %v", e, a) + } + if e, a := c.Attempt, attempt; e != a { + t.Errorf("expect %v attempt, got %v", e, a) + } + return c.Backoff.BackoffDelay(attempt, err) + }) + }) + + delay, err := r.RetryDelay(c.Attempt, c.Err) + if c.ExpectErr != nil { + if e, a := c.ExpectErr.Error(), err.Error(); e != a { + t.Errorf("expect %v error, got %v", e, a) + } + } else { + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + } + + if e, a := c.ExpectDelay, delay; e != a { + t.Errorf("expect %v delay, got %v", e, a) + } + }) + } +} diff --git a/aws/retry/timeout_error.go b/aws/retry/timeout_error.go new file mode 100644 index 00000000000..3d47870d2dc --- /dev/null +++ b/aws/retry/timeout_error.go @@ -0,0 +1,52 @@ +package retry + +import ( + "errors" + + "github.com/aws/aws-sdk-go-v2/aws" +) + +// IsErrorTimeout provides the interface of an implementation to determine if +// a error matches. +type IsErrorTimeout interface { + IsErrorTimeout(err error) aws.Ternary +} + +// IsErrorTimeouts is a collection of checks to determine of the error is +// retryable. Iterates through the checks and returns the state of retryable +// if any check returns something other than unknown. +type IsErrorTimeouts []IsErrorTimeout + +// IsErrorTimeout returns if the error is retryable if any of the checks in +// the list return a value other than unknown. +func (ts IsErrorTimeouts) IsErrorTimeout(err error) aws.Ternary { + for _, t := range ts { + if v := t.IsErrorTimeout(err); v != aws.UnknownTernary { + return v + } + } + return aws.UnknownTernary +} + +// IsErrorTimeoutFunc wraps a function with the IsErrorTimeout interface. +type IsErrorTimeoutFunc func(error) aws.Ternary + +// IsErrorTimeout returns if the error is retryable. +func (fn IsErrorTimeoutFunc) IsErrorTimeout(err error) aws.Ternary { + return fn(err) +} + +// TimeouterError provides the IsErrorTimeout implementation for determining if +// an error is a timeout based on type with the Timeout method. +type TimeouterError struct{} + +// IsErrorTimeout returns if the error is a timeout error. +func (t TimeouterError) IsErrorTimeout(err error) aws.Ternary { + var v interface{ Timeout() bool } + + if !errors.As(err, &v) { + return aws.UnknownTernary + } + + return aws.BoolTernary(v.Timeout()) +} diff --git a/aws/retry/timeout_error_test.go b/aws/retry/timeout_error_test.go new file mode 100644 index 00000000000..423d81d6b04 --- /dev/null +++ b/aws/retry/timeout_error_test.go @@ -0,0 +1,46 @@ +package retry + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" +) + +type mockTimeoutErr struct{ timeout bool } + +func (m mockTimeoutErr) Timeout() bool { return m.timeout } +func (m mockTimeoutErr) Error() string { + return fmt.Sprintf("mock timeout, %t", m.timeout) +} + +func TestIsTimeoutError(t *testing.T) { + cases := map[string]struct { + Err error + Check IsErrorTimeout + Expect aws.Ternary + }{ + "TimeouterError true": { + Err: fmt.Errorf("nested error, %w", mockTimeoutErr{timeout: true}), + Check: TimeouterError{}, + Expect: aws.TrueTernary, + }, + "TimeouterError false": { + Err: fmt.Errorf("nested error, %w", mockTimeoutErr{timeout: false}), + Check: TimeouterError{}, + Expect: aws.FalseTernary, + }, + "other error": { + Err: fmt.Errorf("some other error"), + Check: TimeouterError{}, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if e, a := c.Expect, c.Check.IsErrorTimeout(c.Err); e != a { + t.Errorf("expect %v, got %v", e, a) + } + }) + } +} diff --git a/aws/retryer.go b/aws/retryer.go index 2e8abf3c287..e8be64265c6 100644 --- a/aws/retryer.go +++ b/aws/retryer.go @@ -1,264 +1,62 @@ package aws import ( - "net" - "net/url" - "strings" + "context" + "fmt" "time" - - "github.com/aws/aws-sdk-go-v2/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. +// Retryer is an interface to determine if a given error from a +// request should be retried, and if so what backoff delay to apply. The +// default implementation used by most services is the retry package's Standard +// type. Which contains basic retry logic using exponential backoff. type Retryer interface { + // IsErrorRetryable returns if the failed request is retryable. This check + // should determine if the error can be retried, or if the error is + // terminal. + IsErrorRetryable(error) bool - // RetryRules return the retry delay that should be used by the SDK before - // making another request attempt for the failed request. - RetryRules(*Request) time.Duration - - // ShouldRetry returns if the failed request is retryable. - // - // Implementations may consider request attempt count when determining if a - // request is retryable, but the SDK will use MaxRetries to limit the - // number of attempts a request are made. - ShouldRetry(*Request) bool + // MaxAttempts returns the maximum number of attempts that can be made for + // a request before failing. A value of 0 implies that the request should + // be retried until it succeeds if the errors are retryable. + MaxAttempts() int - // MaxRetries is the number of times a request may be retried before - // failing. - MaxRetries() int -} + // RetryDelay returns the delay that should be used before retrying the + // request. Will return error if the if the delay could not be determined. + RetryDelay(attempt int, opErr error) (time.Duration, error) -// 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 -} + // GetRetryToken attempts to deduct the retry cost from the retry token pool. + // Returning the token release function, or error. + GetRetryToken(ctx context.Context, opErr error) (releaseToken func(error) error, err error) -var throttleCodes = map[string]struct{}{ - "ProvisionedThroughputExceededException": {}, - "Throttling": {}, - "ThrottlingException": {}, - "RequestLimitExceeded": {}, - "RequestThrottled": {}, - "RequestThrottledException": {}, - "TooManyRequestsException": {}, // Lambda functions - "PriorRequestNotComplete": {}, // Route53 + // GetInitalToken returns the initial request token that can increment the + // retry token pool if the request is successful. + GetInitialToken() (releaseToken func(error) error) } -// 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 -} +// NoOpRetryer provides a RequestRetryDecider implementation that will flag +// all attempt errors as not retryable, with a max attempts of 1. +type NoOpRetryer struct{} -func isCodeThrottle(code string) bool { - _, ok := throttleCodes[code] - return ok -} +// IsErrorRetryable returns false for all error values. +func (NoOpRetryer) IsErrorRetryable(error) bool { return false } -func isCodeRetryable(code string) bool { - if _, ok := retryableCodes[code]; ok { - return true - } +// MaxAttempts always returns 1 for the original request attempt. +func (NoOpRetryer) MaxAttempts() int { return 1 } - return isCodeExpiredCreds(code) +// RetryDelay is not valid for the NoOpRetryer. Will always return error. +func (NoOpRetryer) RetryDelay(int, error) (time.Duration, error) { + return 0, fmt.Errorf("not retrying any request errors") } -func isCodeExpiredCreds(code string) bool { - _, ok := credsExpiredCodes[code] - return ok +// GetRetryToken returns a stub function that does nothing. +func (NoOpRetryer) GetRetryToken(context.Context, error) (func(error) error, error) { + return nopReleaseToken, nil } -var validParentCodes = map[string]struct{}{ - ErrCodeSerialization: {}, - ErrCodeRead: {}, +// GetInitialToken returns a stub function that does nothing. +func (NoOpRetryer) GetInitialToken() func(error) error { + return nopReleaseToken } -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.(temporary); ok { - return t.Temporary() || isErrConnectionReset(err) - } - - 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 { - return false - } - return shouldRetryError(err) -} - -type temporary interface { - Temporary() bool -} - -func shouldRetryError(origErr error) bool { - switch err := origErr.(type) { - case awserr.Error: - if err.Code() == ErrCodeRequestCanceled { - return false - } - if isNestedErrorRetryable(err) { - return true - } - - origErr := err.OrigErr() - var shouldRetry bool - if origErr != nil { - shouldRetry := shouldRetryError(origErr) - if err.Code() == "RequestError" && !shouldRetry { - return false - } - } - if isCodeRetryable(err.Code()) { - return true - } - return shouldRetry - - case *url.Error: - if strings.Contains(err.Error(), "connection refused") { - // Refused connections should be retried as the service may not yet - // be running on the port. Go TCP dial considers refused - // connections as not temporary. - return true - } - // *url.Error only implements Temporary after golang 1.6 but since - // url.Error only wraps the error: - // Todo: Investigate use case for this error case for +Go1.11 - return shouldRetryError(err.Err) - - case temporary: - if netErr, ok := err.(*net.OpError); ok && netErr.Op == "dial" { - return true - } - // If the error is temporary, we want to allow continuation of the - // retry process - return err.Temporary() || isErrConnectionReset(origErr) - - case nil: - // `awserr.Error.OrigErr()` can be nil, meaning there was an error but - // because we don't know the cause, it is marked as retryable. See - // TestRequest4xxUnretryable for an example. - return true - - default: - if strings.Contains(err.Error(), "canceled") { - return false - } - // here we don't know the error; so we allow a retry. - return true - } -} - -// 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 aerr, ok := err.(awserr.Error); ok && aerr != nil { - 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 aerr, ok := err.(awserr.Error); ok && aerr != nil { - 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 { - if isErrCode(r.Error, r.RetryErrorCodes) { - return true - } - - // HTTP response status code 501 should not be retried. - // 501 represents Not Implemented which means the request method is not - // supported by the server and cannot be handled. - if r.HTTPResponse != nil { - // HTTP response status code 500 represents internal server error and - // should be retried without any throttle. - if r.HTTPResponse.StatusCode == 500 { - return true - } - - } - - 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 { - if isErrCode(r.Error, r.ThrottleErrorCodes) { - return true - } - - if r.HTTPResponse != nil { - switch r.HTTPResponse.StatusCode { - case - 429, // error caused due to too many requests, thus retry should be throttled - 502, // Bad Gateway error should be throttled - 503, // caused when service is unavailable, thus retry should be throttled - 504: // error occurred due to gateway timeout, thus retry should be throttled - return true - } - } - - return IsErrorThrottle(r.Error) -} - -func isErrCode(err error, codes []string) bool { - if aerr, ok := err.(awserr.Error); ok && aerr != nil { - for _, code := range codes { - if code == aerr.Code() { - return true - } - } - } - - return false -} - -// 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) -} +func nopReleaseToken(error) error { return nil } diff --git a/aws/retryer_test.go b/aws/retryer_test.go index 7b69012c7b9..19d14e0e8f9 100644 --- a/aws/retryer_test.go +++ b/aws/retryer_test.go @@ -1,62 +1,3 @@ package aws -import ( - "errors" - "fmt" - "testing" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" -) - -func TestRequestThrottling(t *testing.T) { - req := Request{} - - req.Error = awserr.New("Throttling", "", nil) - if e, a := true, req.IsErrorThrottle(); e != a { - t.Errorf("expect %t to be throttled, was %t", e, a) - } -} - -type mockTempError bool - -func (e mockTempError) Error() string { - return fmt.Sprintf("mock temporary error: %t", e.Temporary()) -} -func (e mockTempError) Temporary() bool { - return bool(e) -} - -func TestIsErrorRetryable(t *testing.T) { - cases := []struct { - Err error - Retryable bool - }{ - { - Err: awserr.New(ErrCodeSerialization, "temporary error", mockTempError(true)), - Retryable: true, - }, - { - Err: awserr.New(ErrCodeSerialization, "temporary error", mockTempError(false)), - Retryable: false, - }, - { - Err: awserr.New(ErrCodeSerialization, "some error", errors.New("blah")), - Retryable: false, - }, - { - Err: awserr.New("SomeError", "some error", nil), - Retryable: false, - }, - { - Err: awserr.New("RequestError", "some error", nil), - Retryable: true, - }, - } - - for i, c := range cases { - retryable := IsErrorRetryable(c.Err) - if e, a := c.Retryable, retryable; e != a { - t.Errorf("%d, expect %t temporary error, got %t", i, e, a) - } - } -} +// TODO put tests for SDK retry behavior with request. diff --git a/aws/stscreds/provider_test.go b/aws/stscreds/provider_test.go index e66d74fb48d..a554dfd1609 100644 --- a/aws/stscreds/provider_test.go +++ b/aws/stscreds/provider_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/service/sts" ) @@ -28,6 +29,7 @@ func (s *stubSTS) AssumeRoleRequest(input *sts.AssumeRoleInput) sts.AssumeRoleRe r, _ := http.NewRequest("POST", "https://sts.amazonaws.com", nil) return r }(), + Retryer: retry.NewStandard(), Handlers: func() aws.Handlers { h := aws.Handlers{} diff --git a/aws/stscreds/web_identity_provider.go b/aws/stscreds/web_identity_provider.go index dbd08f4bf92..c212b21656d 100644 --- a/aws/stscreds/web_identity_provider.go +++ b/aws/stscreds/web_identity_provider.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/aws-sdk-go-v2/service/sts/stsiface" @@ -102,7 +103,7 @@ func (p *WebIdentityRoleProvider) retrieveFn(ctx context.Context) (aws.Credentia // InvalidIdentityToken error is a temporary error that can occur // when assuming an Role with a JWT web identity token. - req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException) + req.Retryer = retry.AddWithErrorCodes(req.Retryer, sts.ErrCodeInvalidIdentityTokenException) resp, err := req.Send(ctx) if err != nil { return aws.Credentials{}, awserr.New(ErrCodeWebIdentity, "failed to retrieve credentials", err) diff --git a/aws/timeout_read_closer.go b/aws/timeout_read_closer.go index d8b5124ee5a..fa2a82dc1d1 100644 --- a/aws/timeout_read_closer.go +++ b/aws/timeout_read_closer.go @@ -1,16 +1,9 @@ package aws import ( + "fmt" "io" "time" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" -) - -var timeoutErr = awserr.New( - ErrCodeResponseTimeout, - "read on body has reached the timeout limit", - nil, ) type readResult struct { @@ -18,6 +11,20 @@ type readResult struct { err error } +// ResponseTimeoutError is an error when the reads from the response are +// delayed longer than the timeout the read was configured for. +type ResponseTimeoutError struct { + TimeoutDur time.Duration +} + +// Timeout returns that the error is was caused by a timeout, and can be +// retried. +func (*ResponseTimeoutError) Timeout() bool { return true } + +func (e *ResponseTimeoutError) Error() string { + return fmt.Sprintf("read on body reach timeout limit, %v", e.TimeoutDur) +} + // timeoutReadCloser will handle body reads that take too long. // We will return a ErrReadTimeout error if a timeout occurs. type timeoutReadCloser struct { @@ -42,7 +49,7 @@ func (r *timeoutReadCloser) Read(b []byte) (int, error) { case data := <-c: return data.n, data.err case <-timer.C: - return 0, timeoutErr + return 0, &ResponseTimeoutError{TimeoutDur: r.duration} } } @@ -56,17 +63,6 @@ const ( HandlerResponseTimeout = "ResponseTimeoutHandler" ) -// adaptToResponseTimeoutError is a handler that will replace any top level error -// to a ErrCodeResponseTimeout, if its child is that. -func adaptToResponseTimeoutError(req *Request) { - if err, ok := req.Error.(awserr.Error); ok { - aerr, ok := err.OrigErr().(awserr.Error) - if ok && aerr.Code() == ErrCodeResponseTimeout { - req.Error = aerr - } - } -} - // WithResponseReadTimeout is a request option that will wrap the body in a timeout read closer. // This will allow for per read timeouts. If a timeout occurred, we will return the // ErrCodeResponseTimeout. @@ -74,7 +70,6 @@ func adaptToResponseTimeoutError(req *Request) { // svc.PutObjectWithContext(ctx, params, request.WithTimeoutReadCloser(30 * time.Second) func WithResponseReadTimeout(duration time.Duration) Option { return func(r *Request) { - var timeoutHandler = NamedHandler{ HandlerResponseTimeout, func(req *Request) { @@ -87,8 +82,5 @@ func WithResponseReadTimeout(duration time.Duration) Option { // remove the handler so we are not stomping over any new durations. r.Handlers.Send.RemoveByName(HandlerResponseTimeout) r.Handlers.Send.PushBackNamed(timeoutHandler) - - r.Handlers.Unmarshal.PushBack(adaptToResponseTimeoutError) - r.Handlers.UnmarshalError.PushBack(adaptToResponseTimeoutError) } } diff --git a/aws/timeout_read_closer_benchmark_test.go b/aws/timeout_read_closer_benchmark_test.go index b099660af56..8d12fde9bf5 100644 --- a/aws/timeout_read_closer_benchmark_test.go +++ b/aws/timeout_read_closer_benchmark_test.go @@ -8,7 +8,8 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/aws-sdk-go-v2/aws/retry" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -55,8 +56,8 @@ func BenchmarkTimeoutReadCloser(b *testing.B) { cfg, meta, handlers, - aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 5 + retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 5 }), op, &struct { diff --git a/aws/timeout_read_closer_test.go b/aws/timeout_read_closer_test.go index cb860edd5a6..2e8ed21c5a3 100644 --- a/aws/timeout_read_closer_test.go +++ b/aws/timeout_read_closer_test.go @@ -7,8 +7,6 @@ import ( "net/http" "testing" "time" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" ) type testReader struct { @@ -61,6 +59,7 @@ func TestTimeoutReadCloserSameDuration(t *testing.T) { func TestWithResponseReadTimeout(t *testing.T) { r := Request{ + Retryer: NoOpRetryer{}, HTTPResponse: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader(nil)), }, @@ -72,47 +71,9 @@ func TestWithResponseReadTimeout(t *testing.T) { } v, ok := r.HTTPResponse.Body.(*timeoutReadCloser) if !ok { - t.Error("Expected the body to be a timeoutReadCloser") + t.Fatalf("Expected the body to be a timeoutReadCloser, got %T", r.HTTPResponse.Body) } if v.duration != time.Second { t.Errorf("Expected %v, but receive %v\n", time.Second, v.duration) } } - -func TestAdaptToResponseTimeout(t *testing.T) { - testCases := []struct { - childErr error - r Request - expectedRootCode string - }{ - { - childErr: awserr.New(ErrCodeResponseTimeout, "timeout!", nil), - r: Request{ - Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout, "timeout!", nil)), - }, - expectedRootCode: ErrCodeResponseTimeout, - }, - { - childErr: awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil), - r: Request{ - Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil)), - }, - expectedRootCode: "ErrTest", - }, - { - r: Request{ - Error: awserr.New("ErrTest", "FooBar", nil), - }, - expectedRootCode: "ErrTest", - }, - } - - for i, c := range testCases { - adaptToResponseTimeoutError(&c.r) - if aerr, ok := c.r.Error.(awserr.Error); !ok { - t.Errorf("Case %d: Expected 'awserr', but received %v", i+1, c.r.Error) - } else if aerr.Code() != c.expectedRootCode { - t.Errorf("Case %d: Expected %q, but received %s", i+1, c.expectedRootCode, aerr.Code()) - } - } -} diff --git a/aws/types.go b/aws/types.go index 0dfb25bb810..9083fda4232 100644 --- a/aws/types.go +++ b/aws/types.go @@ -1,6 +1,7 @@ package aws import ( + "fmt" "io" "sync" ) @@ -203,3 +204,40 @@ func (b *WriteAtBuffer) Bytes() []byte { defer b.m.Unlock() return b.buf } + +// Ternary is an enum allowing an unknown or none state in addition to a bool's +// true and false. +type Ternary int + +func (t Ternary) String() string { + switch t { + case UnknownTernary: + return "unknown" + case FalseTernary: + return "false" + case TrueTernary: + return "true" + default: + return fmt.Sprintf("unknown value, %d", int(t)) + } +} + +// Bool returns true if the value is TrueTernary, false otherwise. +func (t Ternary) Bool() bool { + return t == TrueTernary +} + +// Enumerations for the values of the Ternary type. +const ( + UnknownTernary Ternary = iota + FalseTernary + TrueTernary +) + +// BoolTernary returns a true or false Ternary value for the bool provided. +func BoolTernary(v bool) Ternary { + if v { + return TrueTernary + } + return FalseTernary +} diff --git a/aws/validation.go b/aws/validation.go index 1f11aa28ff8..66c2df8b4f2 100644 --- a/aws/validation.go +++ b/aws/validation.go @@ -3,8 +3,6 @@ package aws import ( "bytes" "fmt" - - "github.com/aws/aws-sdk-go-v2/aws/awserr" ) const ( @@ -88,14 +86,8 @@ func (e ErrInvalidParams) Error() string { return w.String() } -// OrigErr returns the invalid parameters as a awserr.BatchedErrors value -func (e ErrInvalidParams) OrigErr() error { - return awserr.NewBatchError( - InvalidParameterErrCode, e.Message(), e.OrigErrs()) -} - -// OrigErrs returns a slice of the invalid parameters -func (e ErrInvalidParams) OrigErrs() []error { +// Errs returns a slice of the invalid parameters +func (e ErrInvalidParams) Errs() []error { errs := make([]error, len(e.errs)) for i := 0; i < len(errs); i++ { errs[i] = e.errs[i] @@ -106,7 +98,10 @@ func (e ErrInvalidParams) OrigErrs() []error { // An ErrInvalidParam represents an invalid parameter error type. type ErrInvalidParam interface { - awserr.Error + Error() string + + Code() string + Message() string // Field name the error occurred on. Field() string @@ -141,11 +136,6 @@ func (e *errInvalidParam) Error() string { return fmt.Sprintf("%s: %s", e.code, e.Message()) } -// OrigErr returns nil, Implemented for awserr.Error interface. -func (e *errInvalidParam) OrigErr() error { - return nil -} - // Field Returns the field and context the error occurred. func (e *errInvalidParam) Field() string { field := e.context diff --git a/aws/waiter.go b/aws/waiter.go index d17124bbc57..da53de8e033 100644 --- a/aws/waiter.go +++ b/aws/waiter.go @@ -193,7 +193,7 @@ func (w Waiter) Wait(ctx context.Context) error { // Delay to wait before inspecting the resource again if err := sdk.SleepWithContext(ctx, w.Delay(attempt)); err != nil { - return awserr.New(ErrCodeRequestCanceled, "waiter context canceled", err) + return &RequestCanceledError{Err: err} } } diff --git a/aws/waiter_test.go b/aws/waiter_test.go index ee60be14acf..a990708dc56 100644 --- a/aws/waiter_test.go +++ b/aws/waiter_test.go @@ -3,6 +3,7 @@ package aws_test import ( "bytes" "context" + "errors" "fmt" "io/ioutil" "net/http" @@ -108,7 +109,7 @@ func TestWaiterPathAll(t *testing.T) { w := aws.Waiter{ MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(0), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -178,7 +179,7 @@ func TestWaiterPath(t *testing.T) { w := aws.Waiter{ MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(0), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -248,7 +249,7 @@ func TestWaiterFailure(t *testing.T) { w := aws.Waiter{ MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(0), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -350,7 +351,7 @@ func TestWaiterError(t *testing.T) { w := aws.Waiter{ MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(0), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -417,7 +418,7 @@ func TestWaiterStatus(t *testing.T) { w := aws.Waiter{ MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(0), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -481,7 +482,7 @@ func TestWaiter_WithContextCanceled(t *testing.T) { Name: "TestWaiter", MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(1 * time.Millisecond), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -518,13 +519,13 @@ func TestWaiter_WithContextCanceled(t *testing.T) { } err := w.Wait(ctx) - if err == nil { t.Fatalf("expect waiter to be canceled.") } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expect %q error code, got %q", e, a) + + var ce *aws.RequestCanceledError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } if e, a := 2, reqCount; e != a { t.Errorf("expect %d requests, got %d", e, a) @@ -543,7 +544,7 @@ func TestWaiter_WithContext(t *testing.T) { Name: "TestWaiter", MaxAttempts: 10, Delay: aws.ConstantWaiterDelay(1 * time.Millisecond), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, @@ -589,7 +590,7 @@ func TestWaiter_AttemptsExpires(t *testing.T) { Name: "TestWaiter", MaxAttempts: 2, Delay: aws.ConstantWaiterDelay(1 * time.Millisecond), - SleepWithContext: aws.SleepWithContext, + SleepWithContext: sdk.SleepWithContext, Acceptors: []aws.WaiterAcceptor{ { State: aws.SuccessWaiterState, diff --git a/example/aws/request/withContext/withContext.go b/example/aws/request/withContext/withContext.go index 32b62b33468..1ee306c4d87 100644 --- a/example/aws/request/withContext/withContext.go +++ b/example/aws/request/withContext/withContext.go @@ -4,14 +4,13 @@ package main import ( "context" + "errors" "flag" "fmt" "os" "time" "github.com/aws/aws-sdk-go-v2/aws" - request "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/external" "github.com/aws/aws-sdk-go-v2/service/s3" ) @@ -62,9 +61,8 @@ func main() { }) if _, err := req.Send(ctx); err != nil { - if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.ErrCodeRequestCanceled { - // If the SDK can determine the request or retry delay was canceled - // by a context the ErrCodeRequestCanceled error code will be returned. + var cerr *aws.RequestCanceledError + if errors.As(err, &cerr) { fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err) } else { fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err) diff --git a/example/service/dynamodb/unitTest/unitTest_test.go b/example/service/dynamodb/unitTest/unitTest_test.go index 21405c671b3..b6217689cd3 100644 --- a/example/service/dynamodb/unitTest/unitTest_test.go +++ b/example/service/dynamodb/unitTest/unitTest_test.go @@ -33,9 +33,10 @@ func (fd *fakeDynamoDB) GetItemRequest(input *dynamodb.GetItemInput) dynamodb.Ge } req := dynamodb.GetItemRequest{ Request: &aws.Request{ - Data: output, - Error: fd.err, + Data: output, + Error: fd.err, HTTPRequest: &http.Request{}, + Retryer: aws.NoOpRetryer{}, }, } diff --git a/example/service/sqs/mockingClientsForTests/ifaceExample_test.go b/example/service/sqs/mockingClientsForTests/ifaceExample_test.go index 6102156541b..0b43b793acc 100644 --- a/example/service/sqs/mockingClientsForTests/ifaceExample_test.go +++ b/example/service/sqs/mockingClientsForTests/ifaceExample_test.go @@ -23,6 +23,7 @@ func (m mockedReceiveMsgs) ReceiveMessageRequest(in *sqs.ReceiveMessageInput) sq Request: &aws.Request{ Data: &m.Resp, HTTPRequest: &http.Request{}, + Retryer: aws.NoOpRetryer{}, }, } } diff --git a/go.mod b/go.mod index aa3c365038f..57c5cecb6b5 100644 --- a/go.mod +++ b/go.mod @@ -8,4 +8,4 @@ require ( golang.org/x/net v0.0.0-20200202094626-16171245cfb2 ) -go 1.12 +go 1.13 diff --git a/internal/awstesting/client.go b/internal/awstesting/client.go index 1cd260bd1dc..ada63c33a36 100644 --- a/internal/awstesting/client.go +++ b/internal/awstesting/client.go @@ -2,9 +2,13 @@ package awstesting import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" ) // NewClient creates and initializes a generic service client for testing. func NewClient(cfg aws.Config) *aws.Client { + if cfg.Retryer == nil { + cfg.Retryer = retry.NewStandard() + } return aws.NewClient(cfg, aws.Metadata{ServiceName: "mockService"}) } diff --git a/internal/awstesting/mock/mock.go b/internal/awstesting/mock/mock.go index f3c40d12529..43c0de49525 100644 --- a/internal/awstesting/mock/mock.go +++ b/internal/awstesting/mock/mock.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" ) func init() { @@ -33,6 +34,10 @@ func Config() aws.Config { return config.Copy() } // NewMockClient creates and initializes a client that will connect to the // mock server func NewMockClient(cfg aws.Config) *aws.Client { + if cfg.Retryer == nil { + cfg.Retryer = retry.NewStandard() + } + return aws.NewClient( cfg, aws.Metadata{ diff --git a/internal/rand/rand.go b/internal/rand/rand.go new file mode 100644 index 00000000000..ad3caf6b658 --- /dev/null +++ b/internal/rand/rand.go @@ -0,0 +1,33 @@ +package rand + +import ( + "crypto/rand" + "fmt" + "io" + "math/big" +) + +func init() { + Reader = rand.Reader +} + +// Reader provides a random reader that can reset during testing. +var Reader io.Reader + +var floatMaxBigInt = big.NewInt(1 << 53) + +// Float64 returns a float64 read from an io.Reader source. +func Float64(reader io.Reader) (float64, error) { + bi, err := rand.Int(reader, floatMaxBigInt) + if err != nil { + return 0, fmt.Errorf("failed to read random value, %v", err) + } + + return float64(bi.Int64()) / (1 << 53), nil +} + +// CryptoRandFloat64 returns a random float64 obtained from the crypto rand +// source. +func CryptoRandFloat64() (float64, error) { + return Float64(rand.Reader) +} diff --git a/internal/rand/rand_test.go b/internal/rand/rand_test.go new file mode 100644 index 00000000000..b5d3b7da7f7 --- /dev/null +++ b/internal/rand/rand_test.go @@ -0,0 +1,38 @@ +package rand + +import ( + "bytes" + "io" + "testing" +) + +func TestGitterDelay(t *testing.T) { + maxFloat1 := 1 - 1/float64(1<<53) + + cases := map[string]struct { + Reader io.Reader + Expect float64 + }{ + "floor": { + Reader: bytes.NewReader([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), + Expect: 0, + }, + "ceiling": { + Reader: bytes.NewReader([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), + Expect: maxFloat1, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + d, err := Float64(c.Reader) + if err != nil { + t.Fatalf("expect no error, %v", err) + } + + if e, a := c.Expect, d; e != a { + t.Errorf("expect %v delay, got %v", e, a) + } + }) + } +} diff --git a/internal/s3err/error.go b/internal/s3err/error.go index af5326261d1..ddc25b5ef1f 100644 --- a/internal/s3err/error.go +++ b/internal/s3err/error.go @@ -1,6 +1,7 @@ package s3err import ( + "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" @@ -15,7 +16,7 @@ type RequestFailure struct { hostID string } -// NewRequestFailure returns a request failure error decordated with S3 +// NewRequestFailure returns a request failure error decorated with S3 // specific metadata. func NewRequestFailure(err awserr.RequestFailure, hostID string) *RequestFailure { return &RequestFailure{RequestFailure: err, hostID: hostID} @@ -24,10 +25,7 @@ func NewRequestFailure(err awserr.RequestFailure, hostID string) *RequestFailure func (r RequestFailure) Error() string { extra := fmt.Sprintf("status code: %d, request id: %s, host id: %s", r.StatusCode(), r.RequestID(), r.hostID) - return awserr.SprintError(r.Code(), r.Message(), extra, r.OrigErr()) -} -func (r RequestFailure) String() string { - return r.Error() + return awserr.SprintError(r.Code(), r.Message(), extra, r.Unwrap()) } // HostID returns the HostID request response value. @@ -35,6 +33,11 @@ func (r RequestFailure) HostID() string { return r.hostID } +// Unwrap returns the underling error if there was one. +func (r RequestFailure) Unwrap() error { + return errors.Unwrap(r.RequestFailure) +} + // RequestFailureWrapperHandler returns a handler to rap an // awserr.RequestFailure with the S3 request ID 2 from the response. func RequestFailureWrapperHandler() aws.NamedHandler { diff --git a/internal/sdk/time.go b/internal/sdk/time.go index e5640abd876..e68d6df4d12 100644 --- a/internal/sdk/time.go +++ b/internal/sdk/time.go @@ -8,14 +8,14 @@ import ( func init() { NowTime = time.Now Sleep = time.Sleep - SleepWithContext = DefaultSleepWithContext + SleepWithContext = sleepWithContext } -// NowTime is a value for getting the current time. This value can be overriden +// NowTime is a value for getting the current time. This value can be overridden // for testing mocking out current time. var NowTime func() time.Time -// Sleep is a value for sleeping for a duration. This value can be overriden +// Sleep is a value for sleeping for a duration. This value can be overridden // for testing and mocking out sleep duration. var Sleep func(time.Duration) @@ -23,13 +23,13 @@ var Sleep func(time.Duration) // is canceled. Which ever happens first. If the context is canceled the Context's // error will be returned. // -// This value can be overriden for testing and mocking out sleep duration. +// This value can be overridden for testing and mocking out sleep duration. var SleepWithContext func(context.Context, time.Duration) error -// DefaultSleepWithContext will wait for the timer duration to expire, or the context -// is canceled. Which ever happens first. If the context is canceled the Context's -// error will be returned. -func DefaultSleepWithContext(ctx context.Context, dur time.Duration) error { +// sleepWithContext will wait for the timer duration to expire, or the context +// is canceled. Which ever happens first. If the context is canceled the +// Context's error will be returned. +func sleepWithContext(ctx context.Context, dur time.Duration) error { t := time.NewTimer(dur) defer t.Stop() @@ -42,3 +42,22 @@ func DefaultSleepWithContext(ctx context.Context, dur time.Duration) error { return nil } + +// noOpSleepWithContext does nothing, returns immediately. +func noOpSleepWithContext(context.Context, time.Duration) error { + return nil +} + +func noOpSleep(time.Duration) {} + +// TestingUseNoOpSleep is a utility for disabling sleep across the SDK for +// testing. +func TestingUseNoOpSleep() func() { + SleepWithContext = noOpSleepWithContext + Sleep = noOpSleep + + return func() { + SleepWithContext = sleepWithContext + Sleep = time.Sleep + } +} diff --git a/internal/sdk/time_test.go b/internal/sdk/time_test.go new file mode 100644 index 00000000000..aabcd559181 --- /dev/null +++ b/internal/sdk/time_test.go @@ -0,0 +1,32 @@ +package sdk + +import ( + "context" + "strings" + "testing" + "time" +) + +func TestSleepWithContext(t *testing.T) { + ctx, cancelFn := context.WithCancel(context.Background()) + defer cancelFn() + + err := sleepWithContext(ctx, 1*time.Millisecond) + if err != nil { + t.Errorf("expect context to not be canceled, got %v", err) + } +} + +func TestSleepWithContext_Canceled(t *testing.T) { + ctx, cancelFn := context.WithCancel(context.Background()) + cancelFn() + + err := sleepWithContext(ctx, 10*time.Second) + if err == nil { + t.Fatalf("expect error, did not get one") + } + + if e, a := "context canceled", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v error, got %v", e, a) + } +} diff --git a/internal/sdk/uuid.go b/internal/sdk/uuid.go new file mode 100644 index 00000000000..f590b5d229f --- /dev/null +++ b/internal/sdk/uuid.go @@ -0,0 +1,29 @@ +package sdk + +import ( + "fmt" + + "github.com/aws/aws-sdk-go-v2/internal/rand" +) + +// UUIDVersion4 returns a Version 4 random UUID from the byte slice provided +func UUIDVersion4() (string, error) { + b := make([]byte, 16) + if n, err := rand.Reader.Read(b); err != nil { + return "", fmt.Errorf("unable to get random bytes for UUID, %w", err) + } else if n != len(b) { + return "", fmt.Errorf("unable to get 16 bytes for UUID, got %d", n) + } + + return uuidVersion4(b), nil +} + +func uuidVersion4(u []byte) string { + // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 + // 13th character is "4" + u[6] = (u[6] | 0x40) & 0x4F + // 17th character is "8", "9", "a", or "b" + u[8] = (u[8] | 0x80) & 0xBF + + return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/internal/sdk/uuid_test.go b/internal/sdk/uuid_test.go new file mode 100644 index 00000000000..f46d6894235 --- /dev/null +++ b/internal/sdk/uuid_test.go @@ -0,0 +1,19 @@ +package sdk + +import "testing" + +func TestUUIDVersion4(t *testing.T) { + uuid := uuidVersion4(make([]byte, 16)) + if e, a := `00000000-0000-4000-8000-000000000000`, uuid; e != a { + t.Errorf("expect %v uuid, got %v", e, a) + } + + b := make([]byte, 16) + for i := 0; i < len(b); i++ { + b[i] = 1 + } + uuid = uuidVersion4(b) + if e, a := `01010101-0101-4101-8101-010101010101`, uuid; e != a { + t.Errorf("expect %v uuid, got %v", e, a) + } +} diff --git a/internal/timeconv/duration.go b/internal/timeconv/duration.go new file mode 100644 index 00000000000..5d69db5f249 --- /dev/null +++ b/internal/timeconv/duration.go @@ -0,0 +1,13 @@ +package timeconv + +import "time" + +// FloatSecondsDur converts a fractional seconds to duration. +func FloatSecondsDur(v float64) time.Duration { + return time.Duration(v * float64(time.Second)) +} + +// DurSecondsFloat converts a duration into fractional seconds. +func DurSecondsFloat(d time.Duration) float64 { + return float64(d) / float64(time.Second) +} diff --git a/private/model/api/api.go b/private/model/api/api.go index a921cc59499..9f89c6b0631 100644 --- a/private/model/api/api.go +++ b/private/model/api/api.go @@ -712,6 +712,10 @@ func New(config aws.Config) *{{ .StructName }} { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + {{ if .HasExternalClientConfigFields }} if err := resolveClientConfig(svc, config.ConfigSources); err != nil { panic(fmt.Errorf("failed to resolve service configuration: %v", err)) @@ -793,6 +797,8 @@ func (a *API) ClientGoCode() string { a.AddSDKImport("aws", "crr") } + a.AddSDKImport("aws/retry") + var buf bytes.Buffer err := tplClient.Execute(&buf, a) if err != nil { diff --git a/private/model/api/codegentest/service/awsendpointdiscoverytest/api_client.go b/private/model/api/codegentest/service/awsendpointdiscoverytest/api_client.go index f787943f81a..9c40f57f50c 100644 --- a/private/model/api/codegentest/service/awsendpointdiscoverytest/api_client.go +++ b/private/model/api/codegentest/service/awsendpointdiscoverytest/api_client.go @@ -5,6 +5,7 @@ package awsendpointdiscoverytest import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/crr" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -55,6 +56,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + svc.endpointCache = crr.NewEndpointCache(10) // Handlers diff --git a/private/model/api/codegentest/service/restjsonservice/api_client.go b/private/model/api/codegentest/service/restjsonservice/api_client.go index 99f4e22cb3f..edc1b544bfd 100644 --- a/private/model/api/codegentest/service/restjsonservice/api_client.go +++ b/private/model/api/codegentest/service/restjsonservice/api_client.go @@ -4,6 +4,7 @@ package restjsonservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/private/model/api/codegentest/service/restxmlservice/api_client.go b/private/model/api/codegentest/service/restxmlservice/api_client.go index 4e6e3a848b7..bab8544954b 100644 --- a/private/model/api/codegentest/service/restxmlservice/api_client.go +++ b/private/model/api/codegentest/service/restxmlservice/api_client.go @@ -4,6 +4,7 @@ package restxmlservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restxml" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/private/model/api/codegentest/service/rpcservice/api_client.go b/private/model/api/codegentest/service/rpcservice/api_client.go index db4e9a087c7..39d351b93e2 100644 --- a/private/model/api/codegentest/service/rpcservice/api_client.go +++ b/private/model/api/codegentest/service/rpcservice/api_client.go @@ -4,6 +4,7 @@ package rpcservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/private/protocol/ec2query/build_test.go b/private/protocol/ec2query/build_test.go index d5cea498fdc..483abaf2683 100644 --- a/private/protocol/ec2query/build_test.go +++ b/private/protocol/ec2query/build_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewInputService1ProtocolTest(config aws.Config) *InputService1ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -198,6 +203,10 @@ func NewInputService2ProtocolTest(config aws.Config) *InputService2ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -326,6 +335,10 @@ func NewInputService3ProtocolTest(config aws.Config) *InputService3ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -456,6 +469,10 @@ func NewInputService4ProtocolTest(config aws.Config) *InputService4ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -586,6 +603,10 @@ func NewInputService5ProtocolTest(config aws.Config) *InputService5ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -710,6 +731,10 @@ func NewInputService6ProtocolTest(config aws.Config) *InputService6ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -834,6 +859,10 @@ func NewInputService7ProtocolTest(config aws.Config) *InputService7ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -959,6 +988,10 @@ func NewInputService8ProtocolTest(config aws.Config) *InputService8ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1087,6 +1120,10 @@ func NewInputService9ProtocolTest(config aws.Config) *InputService9ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1287,6 +1324,10 @@ func NewInputService10ProtocolTest(config aws.Config) *InputService10ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1508,6 +1549,10 @@ func NewInputService11ProtocolTest(config aws.Config) *InputService11ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) diff --git a/private/protocol/ec2query/unmarshal_test.go b/private/protocol/ec2query/unmarshal_test.go index e9863fa5ef6..b15391404a4 100644 --- a/private/protocol/ec2query/unmarshal_test.go +++ b/private/protocol/ec2query/unmarshal_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewOutputService1ProtocolTest(config aws.Config) *OutputService1ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -208,6 +213,10 @@ func NewOutputService2ProtocolTest(config aws.Config) *OutputService2ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -331,6 +340,10 @@ func NewOutputService3ProtocolTest(config aws.Config) *OutputService3ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -453,6 +466,10 @@ func NewOutputService4ProtocolTest(config aws.Config) *OutputService4ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -575,6 +592,10 @@ func NewOutputService5ProtocolTest(config aws.Config) *OutputService5ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -697,6 +718,10 @@ func NewOutputService6ProtocolTest(config aws.Config) *OutputService6ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -825,6 +850,10 @@ func NewOutputService7ProtocolTest(config aws.Config) *OutputService7ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -947,6 +976,10 @@ func NewOutputService8ProtocolTest(config aws.Config) *OutputService8ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1069,6 +1102,10 @@ func NewOutputService9ProtocolTest(config aws.Config) *OutputService9ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1191,6 +1228,10 @@ func NewOutputService10ProtocolTest(config aws.Config) *OutputService10ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) @@ -1327,6 +1368,10 @@ func NewOutputService11ProtocolTest(config aws.Config) *OutputService11ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) diff --git a/private/protocol/jsonrpc/build_test.go b/private/protocol/jsonrpc/build_test.go index 98daa1684ee..3c469697ae0 100644 --- a/private/protocol/jsonrpc/build_test.go +++ b/private/protocol/jsonrpc/build_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -74,6 +75,10 @@ func NewInputService1ProtocolTest(config aws.Config) *InputService1ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -200,6 +205,10 @@ func NewInputService2ProtocolTest(config aws.Config) *InputService2ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -330,6 +339,10 @@ func NewInputService3ProtocolTest(config aws.Config) *InputService3ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -538,6 +551,10 @@ func NewInputService4ProtocolTest(config aws.Config) *InputService4ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -664,6 +681,10 @@ func NewInputService5ProtocolTest(config aws.Config) *InputService5ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -1182,6 +1203,10 @@ func NewInputService6ProtocolTest(config aws.Config) *InputService6ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -1306,6 +1331,10 @@ func NewInputService7ProtocolTest(config aws.Config) *InputService7ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -1506,6 +1535,10 @@ func NewInputService8ProtocolTest(config aws.Config) *InputService8ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -1729,6 +1762,10 @@ func NewInputService9ProtocolTest(config aws.Config) *InputService9ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/private/protocol/jsonrpc/unmarshal_test.go b/private/protocol/jsonrpc/unmarshal_test.go index 30c0797c081..203a9b77100 100644 --- a/private/protocol/jsonrpc/unmarshal_test.go +++ b/private/protocol/jsonrpc/unmarshal_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewOutputService1ProtocolTest(config aws.Config) *OutputService1ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -208,6 +213,10 @@ func NewOutputService2ProtocolTest(config aws.Config) *OutputService2ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -340,6 +349,10 @@ func NewOutputService3ProtocolTest(config aws.Config) *OutputService3ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -476,6 +489,10 @@ func NewOutputService4ProtocolTest(config aws.Config) *OutputService4ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -684,6 +701,10 @@ func NewOutputService5ProtocolTest(config aws.Config) *OutputService5ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -806,6 +827,10 @@ func NewOutputService6ProtocolTest(config aws.Config) *OutputService6ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) @@ -928,6 +953,10 @@ func NewOutputService7ProtocolTest(config aws.Config) *OutputService7ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/private/protocol/query/build_test.go b/private/protocol/query/build_test.go index c7b397e4c1e..f9f1991ef64 100644 --- a/private/protocol/query/build_test.go +++ b/private/protocol/query/build_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewInputService1ProtocolTest(config aws.Config) *InputService1ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -360,6 +365,10 @@ func NewInputService2ProtocolTest(config aws.Config) *InputService2ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -490,6 +499,10 @@ func NewInputService3ProtocolTest(config aws.Config) *InputService3ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -690,6 +703,10 @@ func NewInputService4ProtocolTest(config aws.Config) *InputService4ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -898,6 +915,10 @@ func NewInputService5ProtocolTest(config aws.Config) *InputService5ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1022,6 +1043,10 @@ func NewInputService6ProtocolTest(config aws.Config) *InputService6ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1146,6 +1171,10 @@ func NewInputService7ProtocolTest(config aws.Config) *InputService7ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1272,6 +1301,10 @@ func NewInputService8ProtocolTest(config aws.Config) *InputService8ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1396,6 +1429,10 @@ func NewInputService9ProtocolTest(config aws.Config) *InputService9ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1520,6 +1557,10 @@ func NewInputService10ProtocolTest(config aws.Config) *InputService10ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1645,6 +1686,10 @@ func NewInputService11ProtocolTest(config aws.Config) *InputService11ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1769,6 +1814,10 @@ func NewInputService12ProtocolTest(config aws.Config) *InputService12ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1897,6 +1946,10 @@ func NewInputService13ProtocolTest(config aws.Config) *InputService13ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -2413,6 +2466,10 @@ func NewInputService14ProtocolTest(config aws.Config) *InputService14ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -2613,6 +2670,10 @@ func NewInputService15ProtocolTest(config aws.Config) *InputService15ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -2912,6 +2973,10 @@ func NewInputService16ProtocolTest(config aws.Config) *InputService16ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/private/protocol/query/unmarshal_test.go b/private/protocol/query/unmarshal_test.go index 0fac56e9899..64c9a5d023f 100644 --- a/private/protocol/query/unmarshal_test.go +++ b/private/protocol/query/unmarshal_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewOutputService1ProtocolTest(config aws.Config) *OutputService1ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -210,6 +215,10 @@ func NewOutputService2ProtocolTest(config aws.Config) *OutputService2ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -334,6 +343,10 @@ func NewOutputService3ProtocolTest(config aws.Config) *OutputService3ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -457,6 +470,10 @@ func NewOutputService4ProtocolTest(config aws.Config) *OutputService4ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -579,6 +596,10 @@ func NewOutputService5ProtocolTest(config aws.Config) *OutputService5ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -701,6 +722,10 @@ func NewOutputService6ProtocolTest(config aws.Config) *OutputService6ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -823,6 +848,10 @@ func NewOutputService7ProtocolTest(config aws.Config) *OutputService7ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -945,6 +974,10 @@ func NewOutputService8ProtocolTest(config aws.Config) *OutputService8ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1077,6 +1110,10 @@ func NewOutputService9ProtocolTest(config aws.Config) *OutputService9ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1209,6 +1246,10 @@ func NewOutputService10ProtocolTest(config aws.Config) *OutputService10ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1331,6 +1372,10 @@ func NewOutputService11ProtocolTest(config aws.Config) *OutputService11ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1459,6 +1504,10 @@ func NewOutputService12ProtocolTest(config aws.Config) *OutputService12ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1581,6 +1630,10 @@ func NewOutputService13ProtocolTest(config aws.Config) *OutputService13ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1703,6 +1756,10 @@ func NewOutputService14ProtocolTest(config aws.Config) *OutputService14ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1825,6 +1882,10 @@ func NewOutputService15ProtocolTest(config aws.Config) *OutputService15ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -1947,6 +2008,10 @@ func NewOutputService16ProtocolTest(config aws.Config) *OutputService16ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) @@ -2083,6 +2148,10 @@ func NewOutputService17ProtocolTest(config aws.Config) *OutputService17ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/private/protocol/restjson/build_test.go b/private/protocol/restjson/build_test.go index 8474448eb9d..01b2c4ca28e 100644 --- a/private/protocol/restjson/build_test.go +++ b/private/protocol/restjson/build_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewInputService1ProtocolTest(config aws.Config) *InputService1ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -206,6 +211,10 @@ func NewInputService2ProtocolTest(config aws.Config) *InputService2ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -348,6 +357,10 @@ func NewInputService3ProtocolTest(config aws.Config) *InputService3ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -490,6 +503,10 @@ func NewInputService4ProtocolTest(config aws.Config) *InputService4ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -638,6 +655,10 @@ func NewInputService5ProtocolTest(config aws.Config) *InputService5ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -794,6 +815,10 @@ func NewInputService6ProtocolTest(config aws.Config) *InputService6ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -955,6 +980,10 @@ func NewInputService7ProtocolTest(config aws.Config) *InputService7ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1191,6 +1220,10 @@ func NewInputService8ProtocolTest(config aws.Config) *InputService8ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1349,6 +1382,10 @@ func NewInputService9ProtocolTest(config aws.Config) *InputService9ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1540,6 +1577,10 @@ func NewInputService10ProtocolTest(config aws.Config) *InputService10ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1739,6 +1780,10 @@ func NewInputService11ProtocolTest(config aws.Config) *InputService11ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1911,6 +1956,10 @@ func NewInputService12ProtocolTest(config aws.Config) *InputService12ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -2077,6 +2126,10 @@ func NewInputService13ProtocolTest(config aws.Config) *InputService13ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -2311,6 +2364,10 @@ func NewInputService14ProtocolTest(config aws.Config) *InputService14ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -2564,6 +2621,10 @@ func NewInputService15ProtocolTest(config aws.Config) *InputService15ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -2800,6 +2861,10 @@ func NewInputService16ProtocolTest(config aws.Config) *InputService16ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -3465,6 +3530,10 @@ func NewInputService17ProtocolTest(config aws.Config) *InputService17ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -3680,6 +3749,10 @@ func NewInputService18ProtocolTest(config aws.Config) *InputService18ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -3823,6 +3896,10 @@ func NewInputService19ProtocolTest(config aws.Config) *InputService19ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -3965,6 +4042,10 @@ func NewInputService20ProtocolTest(config aws.Config) *InputService20ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -4213,6 +4294,10 @@ func NewInputService21ProtocolTest(config aws.Config) *InputService21ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -4622,6 +4707,10 @@ func NewInputService22ProtocolTest(config aws.Config) *InputService22ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -4965,6 +5054,10 @@ func NewInputService23ProtocolTest(config aws.Config) *InputService23ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -5229,6 +5322,10 @@ func NewInputService24ProtocolTest(config aws.Config) *InputService24ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -5385,6 +5482,10 @@ func NewInputService25ProtocolTest(config aws.Config) *InputService25ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/private/protocol/restjson/unmarshal_test.go b/private/protocol/restjson/unmarshal_test.go index aedf18b161b..668ffaa93f7 100644 --- a/private/protocol/restjson/unmarshal_test.go +++ b/private/protocol/restjson/unmarshal_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewOutputService1ProtocolTest(config aws.Config) *OutputService1ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -287,6 +292,10 @@ func NewOutputService2ProtocolTest(config aws.Config) *OutputService2ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -454,6 +463,10 @@ func NewOutputService3ProtocolTest(config aws.Config) *OutputService3ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -675,6 +688,10 @@ func NewOutputService4ProtocolTest(config aws.Config) *OutputService4ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -821,6 +838,10 @@ func NewOutputService5ProtocolTest(config aws.Config) *OutputService5ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -984,6 +1005,10 @@ func NewOutputService6ProtocolTest(config aws.Config) *OutputService6ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1135,6 +1160,10 @@ func NewOutputService7ProtocolTest(config aws.Config) *OutputService7ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1281,6 +1310,10 @@ func NewOutputService8ProtocolTest(config aws.Config) *OutputService8ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1421,6 +1454,10 @@ func NewOutputService9ProtocolTest(config aws.Config) *OutputService9ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1581,6 +1618,10 @@ func NewOutputService10ProtocolTest(config aws.Config) *OutputService10ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1746,6 +1787,10 @@ func NewOutputService11ProtocolTest(config aws.Config) *OutputService11ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -1886,6 +1931,10 @@ func NewOutputService12ProtocolTest(config aws.Config) *OutputService12ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) @@ -2162,6 +2211,10 @@ func NewOutputService13ProtocolTest(config aws.Config) *OutputService13ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/private/protocol/restxml/build_test.go b/private/protocol/restxml/build_test.go index 3c540d2d0f0..92e18607f5b 100644 --- a/private/protocol/restxml/build_test.go +++ b/private/protocol/restxml/build_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewInputService1ProtocolTest(config aws.Config) *InputService1ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -413,6 +418,10 @@ func NewInputService2ProtocolTest(config aws.Config) *InputService2ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -581,6 +590,10 @@ func NewInputService3ProtocolTest(config aws.Config) *InputService3ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -862,6 +875,10 @@ func NewInputService4ProtocolTest(config aws.Config) *InputService4ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1039,6 +1056,10 @@ func NewInputService5ProtocolTest(config aws.Config) *InputService5ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1189,6 +1210,10 @@ func NewInputService6ProtocolTest(config aws.Config) *InputService6ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1339,6 +1364,10 @@ func NewInputService7ProtocolTest(config aws.Config) *InputService7ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1489,6 +1518,10 @@ func NewInputService8ProtocolTest(config aws.Config) *InputService8ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1639,6 +1672,10 @@ func NewInputService9ProtocolTest(config aws.Config) *InputService9ProtocolTest ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1806,6 +1843,10 @@ func NewInputService10ProtocolTest(config aws.Config) *InputService10ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1968,6 +2009,10 @@ func NewInputService11ProtocolTest(config aws.Config) *InputService11ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2185,6 +2230,10 @@ func NewInputService12ProtocolTest(config aws.Config) *InputService12ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2332,6 +2381,10 @@ func NewInputService13ProtocolTest(config aws.Config) *InputService13ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2479,6 +2532,10 @@ func NewInputService14ProtocolTest(config aws.Config) *InputService14ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2634,6 +2691,10 @@ func NewInputService15ProtocolTest(config aws.Config) *InputService15ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2794,6 +2855,10 @@ func NewInputService16ProtocolTest(config aws.Config) *InputService16ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -3028,6 +3093,10 @@ func NewInputService17ProtocolTest(config aws.Config) *InputService17ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -3169,6 +3238,10 @@ func NewInputService18ProtocolTest(config aws.Config) *InputService18ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -3403,6 +3476,10 @@ func NewInputService19ProtocolTest(config aws.Config) *InputService19ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -3843,6 +3920,10 @@ func NewInputService20ProtocolTest(config aws.Config) *InputService20ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -4029,6 +4110,10 @@ func NewInputService21ProtocolTest(config aws.Config) *InputService21ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -4178,6 +4263,10 @@ func NewInputService22ProtocolTest(config aws.Config) *InputService22ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -4412,6 +4501,10 @@ func NewInputService23ProtocolTest(config aws.Config) *InputService23ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -5089,6 +5182,10 @@ func NewInputService24ProtocolTest(config aws.Config) *InputService24ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -5335,6 +5432,10 @@ func NewInputService25ProtocolTest(config aws.Config) *InputService25ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -5676,6 +5777,10 @@ func NewInputService26ProtocolTest(config aws.Config) *InputService26ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -5944,6 +6049,10 @@ func NewInputService27ProtocolTest(config aws.Config) *InputService27ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/private/protocol/restxml/unmarshal_test.go b/private/protocol/restxml/unmarshal_test.go index 8c935aa8ab3..3aa396abc3b 100644 --- a/private/protocol/restxml/unmarshal_test.go +++ b/private/protocol/restxml/unmarshal_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" @@ -72,6 +73,10 @@ func NewOutputService1ProtocolTest(config aws.Config) *OutputService1ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -492,6 +497,10 @@ func NewOutputService2ProtocolTest(config aws.Config) *OutputService2ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -632,6 +641,10 @@ func NewOutputService3ProtocolTest(config aws.Config) *OutputService3ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -777,6 +790,10 @@ func NewOutputService4ProtocolTest(config aws.Config) *OutputService4ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -922,6 +939,10 @@ func NewOutputService5ProtocolTest(config aws.Config) *OutputService5ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1067,6 +1088,10 @@ func NewOutputService6ProtocolTest(config aws.Config) *OutputService6ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1229,6 +1254,10 @@ func NewOutputService7ProtocolTest(config aws.Config) *OutputService7ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1374,6 +1403,10 @@ func NewOutputService8ProtocolTest(config aws.Config) *OutputService8ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1519,6 +1552,10 @@ func NewOutputService9ProtocolTest(config aws.Config) *OutputService9ProtocolTes ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1683,6 +1720,10 @@ func NewOutputService10ProtocolTest(config aws.Config) *OutputService10ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -1822,6 +1863,10 @@ func NewOutputService11ProtocolTest(config aws.Config) *OutputService11ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2026,6 +2071,10 @@ func NewOutputService12ProtocolTest(config aws.Config) *OutputService12ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2165,6 +2214,10 @@ func NewOutputService13ProtocolTest(config aws.Config) *OutputService13ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2385,6 +2438,10 @@ func NewOutputService14ProtocolTest(config aws.Config) *OutputService14ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) @@ -2680,6 +2737,10 @@ func NewOutputService15ProtocolTest(config aws.Config) *OutputService15ProtocolT ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/service/accessanalyzer/api_client.go b/service/accessanalyzer/api_client.go index d9abf974925..dfa3d73d1e3 100644 --- a/service/accessanalyzer/api_client.go +++ b/service/accessanalyzer/api_client.go @@ -4,6 +4,7 @@ package accessanalyzer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/acm/api_client.go b/service/acm/api_client.go index 6b76b193799..040451d3528 100644 --- a/service/acm/api_client.go +++ b/service/acm/api_client.go @@ -4,6 +4,7 @@ package acm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/acmpca/api_client.go b/service/acmpca/api_client.go index 9b65bd91ed2..e318b38fc39 100644 --- a/service/acmpca/api_client.go +++ b/service/acmpca/api_client.go @@ -4,6 +4,7 @@ package acmpca import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/alexaforbusiness/api_client.go b/service/alexaforbusiness/api_client.go index 127383aaebe..713c9ff1f4a 100644 --- a/service/alexaforbusiness/api_client.go +++ b/service/alexaforbusiness/api_client.go @@ -4,6 +4,7 @@ package alexaforbusiness import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/amplify/api_client.go b/service/amplify/api_client.go index 3670263eb4c..f81a494893e 100644 --- a/service/amplify/api_client.go +++ b/service/amplify/api_client.go @@ -4,6 +4,7 @@ package amplify import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/apigateway/api_client.go b/service/apigateway/api_client.go index c5935ed2bf6..29b78b908fd 100644 --- a/service/apigateway/api_client.go +++ b/service/apigateway/api_client.go @@ -4,6 +4,7 @@ package apigateway import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/apigatewaymanagementapi/api_client.go b/service/apigatewaymanagementapi/api_client.go index 26a56075c19..3e3f20d3e17 100644 --- a/service/apigatewaymanagementapi/api_client.go +++ b/service/apigatewaymanagementapi/api_client.go @@ -4,6 +4,7 @@ package apigatewaymanagementapi import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/apigatewayv2/api_client.go b/service/apigatewayv2/api_client.go index f12e64ded7a..9518755fdad 100644 --- a/service/apigatewayv2/api_client.go +++ b/service/apigatewayv2/api_client.go @@ -4,6 +4,7 @@ package apigatewayv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/appconfig/api_client.go b/service/appconfig/api_client.go index c33a57ecd69..377a56f4ad1 100644 --- a/service/appconfig/api_client.go +++ b/service/appconfig/api_client.go @@ -4,6 +4,7 @@ package appconfig import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/applicationautoscaling/api_client.go b/service/applicationautoscaling/api_client.go index 410921a5af1..d3a6a7f04b1 100644 --- a/service/applicationautoscaling/api_client.go +++ b/service/applicationautoscaling/api_client.go @@ -4,6 +4,7 @@ package applicationautoscaling import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/applicationdiscoveryservice/api_client.go b/service/applicationdiscoveryservice/api_client.go index 38a68dd5bd8..8656ad10fba 100644 --- a/service/applicationdiscoveryservice/api_client.go +++ b/service/applicationdiscoveryservice/api_client.go @@ -4,6 +4,7 @@ package applicationdiscoveryservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/applicationinsights/api_client.go b/service/applicationinsights/api_client.go index 8355328acfa..7eddc39fb55 100644 --- a/service/applicationinsights/api_client.go +++ b/service/applicationinsights/api_client.go @@ -4,6 +4,7 @@ package applicationinsights import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/appmesh/api_client.go b/service/appmesh/api_client.go index 1df52848643..9a34812190b 100644 --- a/service/appmesh/api_client.go +++ b/service/appmesh/api_client.go @@ -4,6 +4,7 @@ package appmesh import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/appstream/api_client.go b/service/appstream/api_client.go index 72be51e726b..e3ebe735e70 100644 --- a/service/appstream/api_client.go +++ b/service/appstream/api_client.go @@ -4,6 +4,7 @@ package appstream import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/appsync/api_client.go b/service/appsync/api_client.go index 01e8a7fce50..acd967cd60f 100644 --- a/service/appsync/api_client.go +++ b/service/appsync/api_client.go @@ -4,6 +4,7 @@ package appsync import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/athena/api_client.go b/service/athena/api_client.go index 37cd4d293c7..46c02814df5 100644 --- a/service/athena/api_client.go +++ b/service/athena/api_client.go @@ -4,6 +4,7 @@ package athena import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/autoscaling/api_client.go b/service/autoscaling/api_client.go index b4f0401679c..4d9233cfc3e 100644 --- a/service/autoscaling/api_client.go +++ b/service/autoscaling/api_client.go @@ -4,6 +4,7 @@ package autoscaling import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/autoscalingplans/api_client.go b/service/autoscalingplans/api_client.go index 8a6860831e8..f55cfd6ea23 100644 --- a/service/autoscalingplans/api_client.go +++ b/service/autoscalingplans/api_client.go @@ -4,6 +4,7 @@ package autoscalingplans import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/backup/api_client.go b/service/backup/api_client.go index c8515d20d53..7111979591b 100644 --- a/service/backup/api_client.go +++ b/service/backup/api_client.go @@ -4,6 +4,7 @@ package backup import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/batch/api_client.go b/service/batch/api_client.go index 1fb63032a3b..939942fbb7c 100644 --- a/service/batch/api_client.go +++ b/service/batch/api_client.go @@ -4,6 +4,7 @@ package batch import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/budgets/api_client.go b/service/budgets/api_client.go index ae0dae112c2..ba7a53199f7 100644 --- a/service/budgets/api_client.go +++ b/service/budgets/api_client.go @@ -4,6 +4,7 @@ package budgets import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/chime/api_client.go b/service/chime/api_client.go index 1995a43f583..1dd7de38ef2 100644 --- a/service/chime/api_client.go +++ b/service/chime/api_client.go @@ -4,6 +4,7 @@ package chime import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/cloud9/api_client.go b/service/cloud9/api_client.go index f6f9569865d..e1cee436846 100644 --- a/service/cloud9/api_client.go +++ b/service/cloud9/api_client.go @@ -4,6 +4,7 @@ package cloud9 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/clouddirectory/api_client.go b/service/clouddirectory/api_client.go index 2890d70eb3c..4e2ab07992f 100644 --- a/service/clouddirectory/api_client.go +++ b/service/clouddirectory/api_client.go @@ -4,6 +4,7 @@ package clouddirectory import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/cloudformation/api_client.go b/service/cloudformation/api_client.go index a06feca765e..f36eec06b23 100644 --- a/service/cloudformation/api_client.go +++ b/service/cloudformation/api_client.go @@ -4,6 +4,7 @@ package cloudformation import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/cloudfront/api_client.go b/service/cloudfront/api_client.go index 105e9d60f6c..05756a17d73 100644 --- a/service/cloudfront/api_client.go +++ b/service/cloudfront/api_client.go @@ -4,6 +4,7 @@ package cloudfront import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restxml" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/service/cloudhsm/api_client.go b/service/cloudhsm/api_client.go index 1d8f800d273..87a69c7643d 100644 --- a/service/cloudhsm/api_client.go +++ b/service/cloudhsm/api_client.go @@ -4,6 +4,7 @@ package cloudhsm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cloudhsmv2/api_client.go b/service/cloudhsmv2/api_client.go index d6e3e289625..a454965978a 100644 --- a/service/cloudhsmv2/api_client.go +++ b/service/cloudhsmv2/api_client.go @@ -4,6 +4,7 @@ package cloudhsmv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cloudsearch/api_client.go b/service/cloudsearch/api_client.go index e2e7e0f9637..99ea2eb09e4 100644 --- a/service/cloudsearch/api_client.go +++ b/service/cloudsearch/api_client.go @@ -4,6 +4,7 @@ package cloudsearch import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/cloudsearchdomain/api_client.go b/service/cloudsearchdomain/api_client.go index e33a9de70f8..c48c61f260e 100644 --- a/service/cloudsearchdomain/api_client.go +++ b/service/cloudsearchdomain/api_client.go @@ -4,6 +4,7 @@ package cloudsearchdomain import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/cloudtrail/api_client.go b/service/cloudtrail/api_client.go index 193df998220..9cf70f0b154 100644 --- a/service/cloudtrail/api_client.go +++ b/service/cloudtrail/api_client.go @@ -4,6 +4,7 @@ package cloudtrail import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cloudwatch/api_client.go b/service/cloudwatch/api_client.go index e22ab9dba02..79289f88ece 100644 --- a/service/cloudwatch/api_client.go +++ b/service/cloudwatch/api_client.go @@ -4,6 +4,7 @@ package cloudwatch import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/cloudwatchevents/api_client.go b/service/cloudwatchevents/api_client.go index e23f692fbf4..7c1eb733e49 100644 --- a/service/cloudwatchevents/api_client.go +++ b/service/cloudwatchevents/api_client.go @@ -4,6 +4,7 @@ package cloudwatchevents import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cloudwatchlogs/api_client.go b/service/cloudwatchlogs/api_client.go index a84b260daeb..5cc58bcc3ee 100644 --- a/service/cloudwatchlogs/api_client.go +++ b/service/cloudwatchlogs/api_client.go @@ -4,6 +4,7 @@ package cloudwatchlogs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codebuild/api_client.go b/service/codebuild/api_client.go index e11dfc5f8ff..a0c8b1e1253 100644 --- a/service/codebuild/api_client.go +++ b/service/codebuild/api_client.go @@ -4,6 +4,7 @@ package codebuild import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codecommit/api_client.go b/service/codecommit/api_client.go index 8683b213840..47d5b4fb3ee 100644 --- a/service/codecommit/api_client.go +++ b/service/codecommit/api_client.go @@ -4,6 +4,7 @@ package codecommit import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codedeploy/api_client.go b/service/codedeploy/api_client.go index 5d66c0ff2d8..8dff4fc9db0 100644 --- a/service/codedeploy/api_client.go +++ b/service/codedeploy/api_client.go @@ -4,6 +4,7 @@ package codedeploy import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codeguruprofiler/api_client.go b/service/codeguruprofiler/api_client.go index a35d4c573cb..c8975911f12 100644 --- a/service/codeguruprofiler/api_client.go +++ b/service/codeguruprofiler/api_client.go @@ -4,6 +4,7 @@ package codeguruprofiler import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/codegurureviewer/api_client.go b/service/codegurureviewer/api_client.go index 2cfab9ac061..d54979dfb5f 100644 --- a/service/codegurureviewer/api_client.go +++ b/service/codegurureviewer/api_client.go @@ -4,6 +4,7 @@ package codegurureviewer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/codepipeline/api_client.go b/service/codepipeline/api_client.go index 54ae0ae4591..07a5dc85675 100644 --- a/service/codepipeline/api_client.go +++ b/service/codepipeline/api_client.go @@ -4,6 +4,7 @@ package codepipeline import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codestar/api_client.go b/service/codestar/api_client.go index 1ed18af6f3d..60333f5e683 100644 --- a/service/codestar/api_client.go +++ b/service/codestar/api_client.go @@ -4,6 +4,7 @@ package codestar import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codestarconnections/api_client.go b/service/codestarconnections/api_client.go index 0fbce8a9692..a7a87d27bd9 100644 --- a/service/codestarconnections/api_client.go +++ b/service/codestarconnections/api_client.go @@ -4,6 +4,7 @@ package codestarconnections import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/codestarnotifications/api_client.go b/service/codestarnotifications/api_client.go index a0828dd143a..e071952c3b1 100644 --- a/service/codestarnotifications/api_client.go +++ b/service/codestarnotifications/api_client.go @@ -4,6 +4,7 @@ package codestarnotifications import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/cognitoidentity/api_client.go b/service/cognitoidentity/api_client.go index b7b459ce7dd..bebc7ae1e70 100644 --- a/service/cognitoidentity/api_client.go +++ b/service/cognitoidentity/api_client.go @@ -4,6 +4,7 @@ package cognitoidentity import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cognitoidentityprovider/api_client.go b/service/cognitoidentityprovider/api_client.go index 6c3746b9c9a..d24e0e50c95 100644 --- a/service/cognitoidentityprovider/api_client.go +++ b/service/cognitoidentityprovider/api_client.go @@ -4,6 +4,7 @@ package cognitoidentityprovider import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/cognitosync/api_client.go b/service/cognitosync/api_client.go index ba00fd2bf6d..f2c911c2ffd 100644 --- a/service/cognitosync/api_client.go +++ b/service/cognitosync/api_client.go @@ -4,6 +4,7 @@ package cognitosync import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/comprehend/api_client.go b/service/comprehend/api_client.go index f6aef07ebe3..1fac72267d6 100644 --- a/service/comprehend/api_client.go +++ b/service/comprehend/api_client.go @@ -4,6 +4,7 @@ package comprehend import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/comprehendmedical/api_client.go b/service/comprehendmedical/api_client.go index 06c0c72904d..5e31be8e8ab 100644 --- a/service/comprehendmedical/api_client.go +++ b/service/comprehendmedical/api_client.go @@ -4,6 +4,7 @@ package comprehendmedical import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/computeoptimizer/api_client.go b/service/computeoptimizer/api_client.go index 07897ebfe0a..7e423b592f0 100644 --- a/service/computeoptimizer/api_client.go +++ b/service/computeoptimizer/api_client.go @@ -4,6 +4,7 @@ package computeoptimizer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/configservice/api_client.go b/service/configservice/api_client.go index 606f9e521cd..1590e42c5b1 100644 --- a/service/configservice/api_client.go +++ b/service/configservice/api_client.go @@ -4,6 +4,7 @@ package configservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/connect/api_client.go b/service/connect/api_client.go index db15c938983..ddea543ea67 100644 --- a/service/connect/api_client.go +++ b/service/connect/api_client.go @@ -4,6 +4,7 @@ package connect import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/connectparticipant/api_client.go b/service/connectparticipant/api_client.go index 305b7b005f8..bb160750f7f 100644 --- a/service/connectparticipant/api_client.go +++ b/service/connectparticipant/api_client.go @@ -4,6 +4,7 @@ package connectparticipant import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/costandusagereportservice/api_client.go b/service/costandusagereportservice/api_client.go index 463054ff151..2ee7809652e 100644 --- a/service/costandusagereportservice/api_client.go +++ b/service/costandusagereportservice/api_client.go @@ -4,6 +4,7 @@ package costandusagereportservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/costexplorer/api_client.go b/service/costexplorer/api_client.go index 09f4e2e9f46..8d7ab72860b 100644 --- a/service/costexplorer/api_client.go +++ b/service/costexplorer/api_client.go @@ -4,6 +4,7 @@ package costexplorer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/databasemigrationservice/api_client.go b/service/databasemigrationservice/api_client.go index f43264a46bf..b9afb9e67aa 100644 --- a/service/databasemigrationservice/api_client.go +++ b/service/databasemigrationservice/api_client.go @@ -4,6 +4,7 @@ package databasemigrationservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/dataexchange/api_client.go b/service/dataexchange/api_client.go index 67d37eaf6b0..b9a98119f88 100644 --- a/service/dataexchange/api_client.go +++ b/service/dataexchange/api_client.go @@ -4,6 +4,7 @@ package dataexchange import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/datapipeline/api_client.go b/service/datapipeline/api_client.go index b9a96c9841c..256f2b97980 100644 --- a/service/datapipeline/api_client.go +++ b/service/datapipeline/api_client.go @@ -4,6 +4,7 @@ package datapipeline import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/datasync/api_client.go b/service/datasync/api_client.go index 6afe8973a73..ddce433ad4b 100644 --- a/service/datasync/api_client.go +++ b/service/datasync/api_client.go @@ -4,6 +4,7 @@ package datasync import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/dax/api_client.go b/service/dax/api_client.go index 2e87a989308..3bbb7d60145 100644 --- a/service/dax/api_client.go +++ b/service/dax/api_client.go @@ -4,6 +4,7 @@ package dax import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/detective/api_client.go b/service/detective/api_client.go index 8789cade331..c636a8a6ded 100644 --- a/service/detective/api_client.go +++ b/service/detective/api_client.go @@ -4,6 +4,7 @@ package detective import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/devicefarm/api_client.go b/service/devicefarm/api_client.go index 28a02382d3f..36e3af87aeb 100644 --- a/service/devicefarm/api_client.go +++ b/service/devicefarm/api_client.go @@ -4,6 +4,7 @@ package devicefarm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/directconnect/api_client.go b/service/directconnect/api_client.go index 70f5eece80d..ff6866dacd5 100644 --- a/service/directconnect/api_client.go +++ b/service/directconnect/api_client.go @@ -4,6 +4,7 @@ package directconnect import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/directoryservice/api_client.go b/service/directoryservice/api_client.go index 008df79b7fd..75f6709b727 100644 --- a/service/directoryservice/api_client.go +++ b/service/directoryservice/api_client.go @@ -4,6 +4,7 @@ package directoryservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/dlm/api_client.go b/service/dlm/api_client.go index e85d6abdf4b..0fa803d22f1 100644 --- a/service/dlm/api_client.go +++ b/service/dlm/api_client.go @@ -4,6 +4,7 @@ package dlm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/docdb/api_client.go b/service/docdb/api_client.go index 741025a0f89..94582d9cbd8 100644 --- a/service/docdb/api_client.go +++ b/service/docdb/api_client.go @@ -4,6 +4,7 @@ package docdb import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/dynamodb/api_client.go b/service/dynamodb/api_client.go index 56c4828e5b0..50c7a0081ab 100644 --- a/service/dynamodb/api_client.go +++ b/service/dynamodb/api_client.go @@ -5,6 +5,7 @@ package dynamodb import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/crr" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -60,6 +61,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + svc.endpointCache = crr.NewEndpointCache(10) // Handlers diff --git a/service/dynamodb/customizations.go b/service/dynamodb/customizations.go index 9eb032ee433..5fdec633ba8 100644 --- a/service/dynamodb/customizations.go +++ b/service/dynamodb/customizations.go @@ -6,10 +6,9 @@ import ( "io" "io/ioutil" "strconv" - "time" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" ) func init() { @@ -33,10 +32,7 @@ func init() { } func setCustomRetryer(c *Client) { - c.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 10 - d.MinRetryDelay = 50 * time.Millisecond - }) + c.Retryer = retry.AddWithMaxAttempts(c.Retryer, 10) } func drainBody(b io.ReadCloser, length int64) (out *bytes.Buffer, err error) { @@ -54,13 +50,19 @@ func drainBody(b io.ReadCloser, length int64) (out *bytes.Buffer, err error) { return buf, nil } -var disableCompressionHandler = aws.NamedHandler{Name: "dynamodb.DisableCompression", Fn: disableCompression} +var disableCompressionHandler = aws.NamedHandler{ + Name: "dynamodb.DisableCompression", + Fn: disableCompression, +} func disableCompression(r *aws.Request) { r.HTTPRequest.Header.Set("Accept-Encoding", "identity") } -var validateCRC32Handler = aws.NamedHandler{Name: "dynamodb.ValidateCRC32", Fn: validateCRC32} +var validateCRC32Handler = aws.NamedHandler{ + Name: "dynamodb.ValidateCRC32", + Fn: validateCRC32, +} func validateCRC32(r *aws.Request) { if r.Error != nil { @@ -70,7 +72,7 @@ func validateCRC32(r *aws.Request) { // Try to get CRC from response header := r.HTTPResponse.Header.Get("X-Amz-Crc32") if header == "" { - return // No header, skip + return // No CRC32 header, skip } expected, err := strconv.ParseUint(header, 10, 32) @@ -78,8 +80,11 @@ func validateCRC32(r *aws.Request) { return // Could not determine CRC value, skip } + // TODO this drain body should use a multi-writer to write to the buffer and + // hash at same time. Remove the need for iterating through the bytes a + // second time to compute the hash separately. buf, err := drainBody(r.HTTPResponse.Body, r.HTTPResponse.ContentLength) - if err != nil { // failed to read the response body, skip + if err != nil { // failed to read the response body, skip CRC32 validation. return } @@ -91,7 +96,19 @@ func validateCRC32(r *aws.Request) { if crc != uint32(expected) { // CRC does not match, set a retryable error - r.Retryable = aws.Bool(true) - r.Error = awserr.New("CRC32CheckFailed", "CRC32 integrity check failed", nil) + r.Error = &CRC32CheckFailedError{} } } + +// CRC32CheckFailedError provides the error type for when a DynamoDB operation +// response's doesn't match the precomputed CRC32 value supplied by the +// service's API. +type CRC32CheckFailedError struct{} + +// RetryableError signals that the error should be retried. +func (*CRC32CheckFailedError) RetryableError() bool { + return true +} +func (*CRC32CheckFailedError) Error() string { + return "integrity check failed for CRC32 validation" +} diff --git a/service/dynamodb/customizations_test.go b/service/dynamodb/customizations_test.go index 55258b4ff72..a8bafb86cba 100644 --- a/service/dynamodb/customizations_test.go +++ b/service/dynamodb/customizations_test.go @@ -2,14 +2,16 @@ package dynamodb_test import ( "bytes" + "errors" "io/ioutil" "net/http" "os" "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" + "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/aws-sdk-go-v2/service/dynamodb" ) @@ -17,8 +19,8 @@ var db *dynamodb.Client func TestMain(m *testing.M) { cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 3 }) db = dynamodb.New(cfg) @@ -51,38 +53,32 @@ func TestDefaultRetryRules(t *testing.T) { cfg.Retryer = nil svc := dynamodb.New(cfg) - if e, a := 10, svc.Retryer.MaxRetries(); e != a { + if e, a := 10, svc.Retryer.MaxAttempts(); e != a { t.Errorf("expect %d max retries, got %d", e, a) } } func TestCustomRetryRules(t *testing.T) { cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 1 }) svc := dynamodb.New(cfg) - if e, a := 2, svc.Retryer.MaxRetries(); e != a { + if e, a := 1, svc.Retryer.MaxAttempts(); e != a { t.Errorf("expect %d max retries, got %d", e, a) } } -type testCustomRetryer struct { - aws.DefaultRetryer -} - func TestCustomRetry_FromConfig(t *testing.T) { cfg := unit.Config() - cfg.Retryer = testCustomRetryer{aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 9. - })} + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 9 + }) svc := dynamodb.New(cfg) - retryer := svc.Retryer.(testCustomRetryer) - - if e, a := 9, retryer.MaxRetries(); e != a { + if e, a := 9, svc.Retryer.MaxAttempts(); e != a { t.Errorf("expect %d max retries from custom retryer, got %d", e, a) } } @@ -107,9 +103,8 @@ func TestValidateCRC32AlreadyErrorSkip(t *testing.T) { t.Fatalf("expect error, but got none") } - aerr := req.Error.(awserr.Error) - if aerr.Code() == "CRC32CheckFailed" { - t.Errorf("expect error code not to be CRC32CheckFailed") + if e, a := (&dynamodb.CRC32CheckFailedError{}), req.Error; errors.Is(a, e) { + t.Fatalf("expect error not to be %T", e) } } @@ -127,30 +122,27 @@ func TestValidateCRC32IsValid(t *testing.T) { } func TestValidateCRC32DoesNotMatch(t *testing.T) { + cleanup := sdk.TestingUseNoOpSleep() + defer cleanup() + req := mockCRCResponse(db, 200, "{}", "1234") if req.Error == nil { t.Fatalf("expect error, but got none") } req.Handlers.Build.RemoveByName("crr.endpointdiscovery") - aerr := req.Error.(awserr.Error) - if e, a := "CRC32CheckFailed", aerr.Code(); e != a { - t.Errorf("expect %s error code, got %s", e, a) - } if e, a := 2, req.RetryCount; e != a { t.Errorf("expect %d retry count, got %d", e, a) } + if e, a := (&dynamodb.CRC32CheckFailedError{}), req.Error; !errors.Is(a, e) { + t.Fatalf("expect %T error, got %T", e, a) + } } func TestValidateCRC32DoesNotMatchNoComputeChecksum(t *testing.T) { - cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 2 - }) - - svc := dynamodb.New(cfg) + svc := new(dynamodb.Client) + *svc = *db svc.DisableComputeChecksums = true - svc.Handlers.Send.Clear() // mock sending req := mockCRCResponse(svc, 200, `{"TableNames":["A"]}`, "1234") if req.Error != nil { diff --git a/service/dynamodbstreams/api_client.go b/service/dynamodbstreams/api_client.go index 66207470a2c..a2cf77da70a 100644 --- a/service/dynamodbstreams/api_client.go +++ b/service/dynamodbstreams/api_client.go @@ -4,6 +4,7 @@ package dynamodbstreams import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/ebs/api_client.go b/service/ebs/api_client.go index d503c528bd6..54e1ca49295 100644 --- a/service/ebs/api_client.go +++ b/service/ebs/api_client.go @@ -4,6 +4,7 @@ package ebs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/ec2/api_client.go b/service/ec2/api_client.go index c48796a5f1a..45074846d29 100644 --- a/service/ec2/api_client.go +++ b/service/ec2/api_client.go @@ -4,6 +4,7 @@ package ec2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/ec2query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) diff --git a/service/ec2/customizations.go b/service/ec2/customizations.go index 935a0cbfbdd..eb6a1116b89 100644 --- a/service/ec2/customizations.go +++ b/service/ec2/customizations.go @@ -7,34 +7,11 @@ import ( "github.com/aws/aws-sdk-go-v2/internal/awsutil" ) -const ( - // customRetryerMaxNumRetries sets max number of retries - customRetryerMaxNumRetries = 3 - - // customRetryerMinRetryDelay sets min retry delay - customRetryerMinRetryDelay = 1 * time.Second - - // customRetryerMaxRetryDelay sets max retry delay - customRetryerMaxRetryDelay = 8 * time.Second -) - -// setRetryerConfig overrides the default Retryer values -func setRetryerConfig(d *aws.DefaultRetryer) { - d.NumMaxRetries = customRetryerMaxNumRetries - d.MinRetryDelay = customRetryerMinRetryDelay - d.MinThrottleDelay = customRetryerMinRetryDelay - d.MaxRetryDelay = customRetryerMaxRetryDelay - d.MaxThrottleDelay = customRetryerMaxRetryDelay -} - func init() { initRequest = func(c *Client, r *aws.Request) { if r.Operation.Name == opCopySnapshot { // fill the PresignedURL parameter r.Handlers.Build.PushFront(fillPresignedURL) } - if c.Config.Retryer == nil && (r.Operation.Name == opModifyNetworkInterfaceAttribute || r.Operation.Name == opAssignPrivateIpAddresses) { - r.Retryer = aws.NewDefaultRetryer(setRetryerConfig) - } } } diff --git a/service/ec2/customizations_test.go b/service/ec2/customizations_test.go index 021e344933e..047e36a0dc7 100644 --- a/service/ec2/customizations_test.go +++ b/service/ec2/customizations_test.go @@ -22,9 +22,10 @@ func TestCopySnapshotPresignedURL(t *testing.T) { func() { defer func() { if r := recover(); r != nil { - t.Fatalf("expect CopySnapshotRequest with nill") + t.Fatalf("expect CopySnapshotRequest with nil") } }() + // Doesn't panic on nil input req := svc.CopySnapshotRequest(nil) req.Sign() @@ -34,14 +35,18 @@ func TestCopySnapshotPresignedURL(t *testing.T) { SourceRegion: aws.String("us-west-1"), SourceSnapshotId: aws.String("snap-id"), }) - req.Sign() + if err := req.Sign(); err != nil { + t.Fatalf("expect no error, got %v", err) + } b, _ := ioutil.ReadAll(req.HTTPRequest.Body) q, _ := url.ParseQuery(string(b)) u, _ := url.QueryUnescape(q.Get("PresignedUrl")) + if e, a := "us-west-2", q.Get("DestinationRegion"); e != a { t.Errorf("expect %v, got %v", e, a) } + if e, a := "us-west-1", q.Get("SourceRegion"); e != a { t.Errorf("expect %v, got %v", e, a) } diff --git a/service/ec2/retryer_test.go b/service/ec2/retryer_test.go deleted file mode 100644 index a7a8389c106..00000000000 --- a/service/ec2/retryer_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package ec2 - -import ( - "testing" - "time" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" -) - -func TestCustomRetryRules(t *testing.T) { - - cfg := unit.Config() - svc := New(cfg) - - req := svc.ModifyNetworkInterfaceAttributeRequest(&ModifyNetworkInterfaceAttributeInput{ - NetworkInterfaceId: aws.String("foo"), - }) - - duration := req.Request.Retryer.RetryRules(req.Request) - if duration < time.Second*1 || duration > time.Second*2 { - t.Errorf("expected duration to be between 1s and 2s, but received %s", duration) - } - - req.Request.RetryCount = 15 - duration = req.Request.Retryer.RetryRules(req.Request) - - if duration < time.Second*4 || duration > time.Second*8 { - t.Errorf("expected duration to be between 4s and 8s, but received %s", duration) - } - -} - -func TestCustomRetryer_WhenRetrierSpecified(t *testing.T) { - svc := New(aws.Config{ - Region: "us-west-2", - Retryer: aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 4 - d.MinThrottleDelay = 50 * time.Millisecond - d.MinRetryDelay = 10 * time.Millisecond - d.MaxThrottleDelay = 200 * time.Millisecond - d.MaxRetryDelay = 300 * time.Millisecond - }), - EndpointResolver: unit.Config().EndpointResolver, - }) - - if _, ok := svc.Client.Retryer.(aws.DefaultRetryer); !ok { - t.Error("expected default retryer, but received otherwise") - } - - req := svc.AssignPrivateIpAddressesRequest(&AssignPrivateIpAddressesInput{ - NetworkInterfaceId: aws.String("foo"), - }) - - d := req.Request.Retryer.(aws.DefaultRetryer) - - if d.NumMaxRetries != 4 { - t.Errorf("expected max retries to be %v, got %v", 4, d.NumMaxRetries) - } - - if d.MinRetryDelay != 10*time.Millisecond { - t.Errorf("expected min retry delay to be %v, got %v", "10 ms", d.MinRetryDelay) - } - - if d.MinThrottleDelay != 50*time.Millisecond { - t.Errorf("expected min throttle delay to be %v, got %v", "50 ms", d.MinThrottleDelay) - } - - if d.MaxRetryDelay != 300*time.Millisecond { - t.Errorf("expected max retry delay to be %v, got %v", "300 ms", d.MaxRetryDelay) - } - - if d.MaxThrottleDelay != 200*time.Millisecond { - t.Errorf("expected max throttle delay to be %v, got %v", "200 ms", d.MaxThrottleDelay) - } -} - -func TestCustomRetryer(t *testing.T) { - - cfg := unit.Config() - svc := New(cfg) - - req := svc.AssignPrivateIpAddressesRequest(&AssignPrivateIpAddressesInput{ - NetworkInterfaceId: aws.String("foo"), - }) - - d := req.Request.Retryer.(aws.DefaultRetryer) - - if d.NumMaxRetries != customRetryerMaxNumRetries { - t.Errorf("expected max retries to be %v, got %v", customRetryerMaxNumRetries, d.NumMaxRetries) - } - - if d.MinRetryDelay != customRetryerMinRetryDelay { - t.Errorf("expected min retry delay to be %v, got %v", customRetryerMinRetryDelay, d.MinRetryDelay) - } - - if d.MinThrottleDelay != customRetryerMinRetryDelay { - t.Errorf("expected min throttle delay to be %v, got %v", customRetryerMinRetryDelay, d.MinThrottleDelay) - } - - if d.MaxRetryDelay != customRetryerMaxRetryDelay { - t.Errorf("expected max retry delay to be %v, got %v", customRetryerMaxRetryDelay, d.MaxRetryDelay) - } - - if d.MaxThrottleDelay != customRetryerMaxRetryDelay { - t.Errorf("expected max throttle delay to be %v, got %v", customRetryerMaxRetryDelay, d.MaxThrottleDelay) - } -} diff --git a/service/ec2instanceconnect/api_client.go b/service/ec2instanceconnect/api_client.go index 0d4b69c67df..f948bfdbee9 100644 --- a/service/ec2instanceconnect/api_client.go +++ b/service/ec2instanceconnect/api_client.go @@ -4,6 +4,7 @@ package ec2instanceconnect import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/ecr/api_client.go b/service/ecr/api_client.go index 225928e8d06..f7fa5613904 100644 --- a/service/ecr/api_client.go +++ b/service/ecr/api_client.go @@ -4,6 +4,7 @@ package ecr import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/ecs/api_client.go b/service/ecs/api_client.go index b6f6c5381e3..197397af369 100644 --- a/service/ecs/api_client.go +++ b/service/ecs/api_client.go @@ -4,6 +4,7 @@ package ecs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/efs/api_client.go b/service/efs/api_client.go index 183815ef02b..3b41f925d93 100644 --- a/service/efs/api_client.go +++ b/service/efs/api_client.go @@ -4,6 +4,7 @@ package efs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/eks/api_client.go b/service/eks/api_client.go index 9e51f823d13..5bbe4d82012 100644 --- a/service/eks/api_client.go +++ b/service/eks/api_client.go @@ -4,6 +4,7 @@ package eks import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/elasticache/api_client.go b/service/elasticache/api_client.go index e87ccf908a2..5a13619030e 100644 --- a/service/elasticache/api_client.go +++ b/service/elasticache/api_client.go @@ -4,6 +4,7 @@ package elasticache import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/elasticbeanstalk/api_client.go b/service/elasticbeanstalk/api_client.go index cefe326a1d7..4f94f1fd3c4 100644 --- a/service/elasticbeanstalk/api_client.go +++ b/service/elasticbeanstalk/api_client.go @@ -4,6 +4,7 @@ package elasticbeanstalk import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/elasticinference/api_client.go b/service/elasticinference/api_client.go index e422c270ec9..83e6dbf788f 100644 --- a/service/elasticinference/api_client.go +++ b/service/elasticinference/api_client.go @@ -4,6 +4,7 @@ package elasticinference import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/elasticloadbalancing/api_client.go b/service/elasticloadbalancing/api_client.go index 6d3aa3869ff..3ce5a0a93fc 100644 --- a/service/elasticloadbalancing/api_client.go +++ b/service/elasticloadbalancing/api_client.go @@ -4,6 +4,7 @@ package elasticloadbalancing import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/elasticloadbalancingv2/api_client.go b/service/elasticloadbalancingv2/api_client.go index 08b6a5a4ce8..87affd6040b 100644 --- a/service/elasticloadbalancingv2/api_client.go +++ b/service/elasticloadbalancingv2/api_client.go @@ -4,6 +4,7 @@ package elasticloadbalancingv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/elasticsearchservice/api_client.go b/service/elasticsearchservice/api_client.go index 4ef771cfba4..b069ed998aa 100644 --- a/service/elasticsearchservice/api_client.go +++ b/service/elasticsearchservice/api_client.go @@ -4,6 +4,7 @@ package elasticsearchservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/elastictranscoder/api_client.go b/service/elastictranscoder/api_client.go index d60e27ad440..25173b2b519 100644 --- a/service/elastictranscoder/api_client.go +++ b/service/elastictranscoder/api_client.go @@ -4,6 +4,7 @@ package elastictranscoder import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/emr/api_client.go b/service/emr/api_client.go index bc6eb8e46ac..c7dcab1ff12 100644 --- a/service/emr/api_client.go +++ b/service/emr/api_client.go @@ -4,6 +4,7 @@ package emr import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/eventbridge/api_client.go b/service/eventbridge/api_client.go index 262bdca5067..57d2bc2c2d0 100644 --- a/service/eventbridge/api_client.go +++ b/service/eventbridge/api_client.go @@ -4,6 +4,7 @@ package eventbridge import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/firehose/api_client.go b/service/firehose/api_client.go index 9aa32f9379a..e844d45169a 100644 --- a/service/firehose/api_client.go +++ b/service/firehose/api_client.go @@ -4,6 +4,7 @@ package firehose import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/fms/api_client.go b/service/fms/api_client.go index 95013de0c79..acfcc39880c 100644 --- a/service/fms/api_client.go +++ b/service/fms/api_client.go @@ -4,6 +4,7 @@ package fms import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/forecast/api_client.go b/service/forecast/api_client.go index 26541754ee0..7cbc28420ec 100644 --- a/service/forecast/api_client.go +++ b/service/forecast/api_client.go @@ -4,6 +4,7 @@ package forecast import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/forecastquery/api_client.go b/service/forecastquery/api_client.go index bddd3ee4d3a..169dfdff2d1 100644 --- a/service/forecastquery/api_client.go +++ b/service/forecastquery/api_client.go @@ -4,6 +4,7 @@ package forecastquery import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/frauddetector/api_client.go b/service/frauddetector/api_client.go index 82038cf37dc..bbf3fb21d32 100644 --- a/service/frauddetector/api_client.go +++ b/service/frauddetector/api_client.go @@ -4,6 +4,7 @@ package frauddetector import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/fsx/api_client.go b/service/fsx/api_client.go index 4404d669b61..eb20f782668 100644 --- a/service/fsx/api_client.go +++ b/service/fsx/api_client.go @@ -4,6 +4,7 @@ package fsx import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/gamelift/api_client.go b/service/gamelift/api_client.go index d76058063e5..583db93f366 100644 --- a/service/gamelift/api_client.go +++ b/service/gamelift/api_client.go @@ -4,6 +4,7 @@ package gamelift import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/glacier/api_client.go b/service/glacier/api_client.go index c8682617b4c..2a2729dedcc 100644 --- a/service/glacier/api_client.go +++ b/service/glacier/api_client.go @@ -4,6 +4,7 @@ package glacier import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/globalaccelerator/api_client.go b/service/globalaccelerator/api_client.go index f4c7729f5ce..1b8f4024370 100644 --- a/service/globalaccelerator/api_client.go +++ b/service/globalaccelerator/api_client.go @@ -4,6 +4,7 @@ package globalaccelerator import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/glue/api_client.go b/service/glue/api_client.go index b2d03ac29d4..d3c530bd007 100644 --- a/service/glue/api_client.go +++ b/service/glue/api_client.go @@ -4,6 +4,7 @@ package glue import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/greengrass/api_client.go b/service/greengrass/api_client.go index e78d4ab6d81..518f529fc10 100644 --- a/service/greengrass/api_client.go +++ b/service/greengrass/api_client.go @@ -4,6 +4,7 @@ package greengrass import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/groundstation/api_client.go b/service/groundstation/api_client.go index 5eb2125d1b8..691dee6c7cc 100644 --- a/service/groundstation/api_client.go +++ b/service/groundstation/api_client.go @@ -4,6 +4,7 @@ package groundstation import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/guardduty/api_client.go b/service/guardduty/api_client.go index a607e3691b0..c52164a7a58 100644 --- a/service/guardduty/api_client.go +++ b/service/guardduty/api_client.go @@ -4,6 +4,7 @@ package guardduty import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/health/api_client.go b/service/health/api_client.go index 78e641582b1..ac76daa9684 100644 --- a/service/health/api_client.go +++ b/service/health/api_client.go @@ -4,6 +4,7 @@ package health import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/iam/api_client.go b/service/iam/api_client.go index 9e7596f4316..1cd116db132 100644 --- a/service/iam/api_client.go +++ b/service/iam/api_client.go @@ -4,6 +4,7 @@ package iam import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/imagebuilder/api_client.go b/service/imagebuilder/api_client.go index 3546b6117e5..f256ea3bff4 100644 --- a/service/imagebuilder/api_client.go +++ b/service/imagebuilder/api_client.go @@ -4,6 +4,7 @@ package imagebuilder import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/inspector/api_client.go b/service/inspector/api_client.go index 58664367e21..c3633ab8783 100644 --- a/service/inspector/api_client.go +++ b/service/inspector/api_client.go @@ -4,6 +4,7 @@ package inspector import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/iot/api_client.go b/service/iot/api_client.go index e3f2bbf944a..099d8417048 100644 --- a/service/iot/api_client.go +++ b/service/iot/api_client.go @@ -4,6 +4,7 @@ package iot import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iot1clickdevicesservice/api_client.go b/service/iot1clickdevicesservice/api_client.go index 7c0254a4689..b2d8faeb524 100644 --- a/service/iot1clickdevicesservice/api_client.go +++ b/service/iot1clickdevicesservice/api_client.go @@ -4,6 +4,7 @@ package iot1clickdevicesservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iot1clickprojects/api_client.go b/service/iot1clickprojects/api_client.go index 907df6f5646..0912c4de2c8 100644 --- a/service/iot1clickprojects/api_client.go +++ b/service/iot1clickprojects/api_client.go @@ -4,6 +4,7 @@ package iot1clickprojects import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iotanalytics/api_client.go b/service/iotanalytics/api_client.go index 8c6735f795f..4c8b3c0055c 100644 --- a/service/iotanalytics/api_client.go +++ b/service/iotanalytics/api_client.go @@ -4,6 +4,7 @@ package iotanalytics import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iotdataplane/api_client.go b/service/iotdataplane/api_client.go index 2179fe4dc67..7482fea0ddd 100644 --- a/service/iotdataplane/api_client.go +++ b/service/iotdataplane/api_client.go @@ -4,6 +4,7 @@ package iotdataplane import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iotevents/api_client.go b/service/iotevents/api_client.go index 64d7662a173..52a869c1f4f 100644 --- a/service/iotevents/api_client.go +++ b/service/iotevents/api_client.go @@ -4,6 +4,7 @@ package iotevents import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/ioteventsdata/api_client.go b/service/ioteventsdata/api_client.go index 8f305c4b017..66146e4e751 100644 --- a/service/ioteventsdata/api_client.go +++ b/service/ioteventsdata/api_client.go @@ -4,6 +4,7 @@ package ioteventsdata import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iotjobsdataplane/api_client.go b/service/iotjobsdataplane/api_client.go index a75d2cc4a03..0f22f48552c 100644 --- a/service/iotjobsdataplane/api_client.go +++ b/service/iotjobsdataplane/api_client.go @@ -4,6 +4,7 @@ package iotjobsdataplane import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/iotsecuretunneling/api_client.go b/service/iotsecuretunneling/api_client.go index 390cf01d72f..d70414abf07 100644 --- a/service/iotsecuretunneling/api_client.go +++ b/service/iotsecuretunneling/api_client.go @@ -4,6 +4,7 @@ package iotsecuretunneling import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/iotthingsgraph/api_client.go b/service/iotthingsgraph/api_client.go index 2ecad280aeb..7014a209d0b 100644 --- a/service/iotthingsgraph/api_client.go +++ b/service/iotthingsgraph/api_client.go @@ -4,6 +4,7 @@ package iotthingsgraph import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/kafka/api_client.go b/service/kafka/api_client.go index 15dc2c6da43..fa11c9e2de2 100644 --- a/service/kafka/api_client.go +++ b/service/kafka/api_client.go @@ -4,6 +4,7 @@ package kafka import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/kendra/api_client.go b/service/kendra/api_client.go index 23c2674fe2a..e9e6feea478 100644 --- a/service/kendra/api_client.go +++ b/service/kendra/api_client.go @@ -4,6 +4,7 @@ package kendra import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/kinesis/api_client.go b/service/kinesis/api_client.go index d8416d269ea..cdac83dcd75 100644 --- a/service/kinesis/api_client.go +++ b/service/kinesis/api_client.go @@ -4,6 +4,7 @@ package kinesis import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/kinesis/customizations.go b/service/kinesis/customizations.go index c51cf746304..2f46579b8e2 100644 --- a/service/kinesis/customizations.go +++ b/service/kinesis/customizations.go @@ -4,17 +4,20 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" ) var readDuration = 5 * time.Second func init() { + initClient = func(c *Client) { + // Service specific error codes. + c.Retryer = retry.AddWithErrorCodes(c.Retryer, ErrCodeLimitExceededException) + } + initRequest = func(c *Client, r *aws.Request) { if r.Operation.Name == opGetRecords { r.ApplyOptions(aws.WithResponseReadTimeout(readDuration)) } - - // Service specific error codes. - r.RetryErrorCodes = append(r.RetryErrorCodes, ErrCodeLimitExceededException) } } diff --git a/service/kinesis/customizations_test.go b/service/kinesis/customizations_test.go index 5228f8ecdbb..7dab591963e 100644 --- a/service/kinesis/customizations_test.go +++ b/service/kinesis/customizations_test.go @@ -3,6 +3,7 @@ package kinesis import ( "bytes" "context" + "errors" "fmt" "io" "io/ioutil" @@ -11,9 +12,10 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" + "github.com/aws/aws-sdk-go-v2/internal/sdk" ) type testReader struct { @@ -32,14 +34,13 @@ func (r *testReader) Close() error { // GetRecords will hang unexpectedly during reads. // See https://github.com/aws/aws-sdk-go-v2/issues/1141 func TestKinesisGetRecordsCustomization(t *testing.T) { + restoreSleep := sdk.TestingUseNoOpSleep() + defer restoreSleep() + readDuration = time.Millisecond - retryCount := 0 + attempts := 0 cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 4 - }) - svc := New(cfg) req := svc.GetRecordsRequest(&GetRecordsInput{ ShardIterator: aws.String("foo"), @@ -55,19 +56,20 @@ func TestKinesisGetRecordsCustomization(t *testing.T) { ContentLength: -1, } r.HTTPResponse.Status = http.StatusText(r.HTTPResponse.StatusCode) - retryCount++ + attempts++ }) req.ApplyOptions(aws.WithResponseReadTimeout(time.Second)) _, err := req.Send(context.Background()) if err == nil { - t.Errorf("Expected error, but received nil") - } else if v, ok := err.(awserr.Error); !ok { - t.Errorf("Expected awserr.Error but received %v", err) - } else if v.Code() != aws.ErrCodeResponseTimeout { - t.Errorf("Expected 'RequestTimeout' error, but received %s instead", v.Code()) + t.Fatalf("expect error, got none") } - if retryCount != 5 { - t.Errorf("Expected '5' retries, but received %d", retryCount) + + if e, a := (*aws.ResponseTimeoutError)(nil), err; !errors.As(a, &e) { + t.Fatalf("expect %T, error in %v", e, a) + } + + if e, a := svc.Retryer.MaxAttempts(), attempts; e != a { + t.Errorf("Expected %v attempts, but received %d", e, a) } } @@ -97,18 +99,16 @@ func TestKinesisGetRecordsNoTimeout(t *testing.T) { } func TestKinesisCustomRetryErrorCodes(t *testing.T) { - cfg := unit.Config() - cfg.LogLevel = aws.LogLevel(aws.LogDebugWithHTTPBody) - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 1 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = 2 }) svc := New(cfg) svc.Handlers.Validate.Clear() const jsonErr = `{"__type":%q, "message":"some error message"}` - var reqCount int + var attempts int resps := []*http.Response{ { StatusCode: 400, @@ -128,16 +128,16 @@ func TestKinesisCustomRetryErrorCodes(t *testing.T) { req.Handlers.Send.Swap(defaults.SendHandler.Name, aws.NamedHandler{ Name: "custom send handler", Fn: func(r *aws.Request) { - r.HTTPResponse = resps[reqCount] - reqCount++ + r.HTTPResponse = resps[attempts] + attempts++ }, }) if _, err := req.Send(context.Background()); err != nil { - t.Fatalf("expect no error, got %v", err) + t.Fatalf("expect no error, got %T, %v", err, err) } - if e, a := 2, reqCount; e != a { + if e, a := 2, attempts; e != a { t.Errorf("expect %v requests, got %v", e, a) } } diff --git a/service/kinesisanalytics/api_client.go b/service/kinesisanalytics/api_client.go index 3f9c13daae5..9d1de662794 100644 --- a/service/kinesisanalytics/api_client.go +++ b/service/kinesisanalytics/api_client.go @@ -4,6 +4,7 @@ package kinesisanalytics import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/kinesisanalyticsv2/api_client.go b/service/kinesisanalyticsv2/api_client.go index e2941bb7db8..a6a0c167f84 100644 --- a/service/kinesisanalyticsv2/api_client.go +++ b/service/kinesisanalyticsv2/api_client.go @@ -4,6 +4,7 @@ package kinesisanalyticsv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/kinesisvideo/api_client.go b/service/kinesisvideo/api_client.go index 2013cfd3191..420614da187 100644 --- a/service/kinesisvideo/api_client.go +++ b/service/kinesisvideo/api_client.go @@ -4,6 +4,7 @@ package kinesisvideo import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/kinesisvideoarchivedmedia/api_client.go b/service/kinesisvideoarchivedmedia/api_client.go index 20595363332..5096b165ef8 100644 --- a/service/kinesisvideoarchivedmedia/api_client.go +++ b/service/kinesisvideoarchivedmedia/api_client.go @@ -4,6 +4,7 @@ package kinesisvideoarchivedmedia import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/kinesisvideomedia/api_client.go b/service/kinesisvideomedia/api_client.go index 62e622a9681..7df09800b49 100644 --- a/service/kinesisvideomedia/api_client.go +++ b/service/kinesisvideomedia/api_client.go @@ -4,6 +4,7 @@ package kinesisvideomedia import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/kinesisvideosignaling/api_client.go b/service/kinesisvideosignaling/api_client.go index deca9d468a1..2aa95d2cde2 100644 --- a/service/kinesisvideosignaling/api_client.go +++ b/service/kinesisvideosignaling/api_client.go @@ -4,6 +4,7 @@ package kinesisvideosignaling import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/kms/api_client.go b/service/kms/api_client.go index 422f83d60c5..bbc1f80f262 100644 --- a/service/kms/api_client.go +++ b/service/kms/api_client.go @@ -4,6 +4,7 @@ package kms import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/lakeformation/api_client.go b/service/lakeformation/api_client.go index 6067b876a8f..3834362f5e8 100644 --- a/service/lakeformation/api_client.go +++ b/service/lakeformation/api_client.go @@ -4,6 +4,7 @@ package lakeformation import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/lambda/api_client.go b/service/lambda/api_client.go index 992a06c7f78..71c466d0a28 100644 --- a/service/lambda/api_client.go +++ b/service/lambda/api_client.go @@ -4,6 +4,7 @@ package lambda import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/lexmodelbuildingservice/api_client.go b/service/lexmodelbuildingservice/api_client.go index 35f67e012d6..b53b4c112d7 100644 --- a/service/lexmodelbuildingservice/api_client.go +++ b/service/lexmodelbuildingservice/api_client.go @@ -4,6 +4,7 @@ package lexmodelbuildingservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/lexruntimeservice/api_client.go b/service/lexruntimeservice/api_client.go index cab8903d69e..0ce8ec94417 100644 --- a/service/lexruntimeservice/api_client.go +++ b/service/lexruntimeservice/api_client.go @@ -4,6 +4,7 @@ package lexruntimeservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/licensemanager/api_client.go b/service/licensemanager/api_client.go index 7dc18d0cacd..1e8f25f705b 100644 --- a/service/licensemanager/api_client.go +++ b/service/licensemanager/api_client.go @@ -4,6 +4,7 @@ package licensemanager import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/lightsail/api_client.go b/service/lightsail/api_client.go index 10ae469e9b3..8c27bb4b22d 100644 --- a/service/lightsail/api_client.go +++ b/service/lightsail/api_client.go @@ -4,6 +4,7 @@ package lightsail import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/machinelearning/api_client.go b/service/machinelearning/api_client.go index 26bac3bf785..6a709e681d1 100644 --- a/service/machinelearning/api_client.go +++ b/service/machinelearning/api_client.go @@ -4,6 +4,7 @@ package machinelearning import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/macie/api_client.go b/service/macie/api_client.go index ec91c950afa..1479e360943 100644 --- a/service/macie/api_client.go +++ b/service/macie/api_client.go @@ -4,6 +4,7 @@ package macie import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/managedblockchain/api_client.go b/service/managedblockchain/api_client.go index 78859e55246..ef97ff92097 100644 --- a/service/managedblockchain/api_client.go +++ b/service/managedblockchain/api_client.go @@ -4,6 +4,7 @@ package managedblockchain import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/marketplacecatalog/api_client.go b/service/marketplacecatalog/api_client.go index d35690e7028..f62e879e228 100644 --- a/service/marketplacecatalog/api_client.go +++ b/service/marketplacecatalog/api_client.go @@ -4,6 +4,7 @@ package marketplacecatalog import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/marketplacecommerceanalytics/api_client.go b/service/marketplacecommerceanalytics/api_client.go index 4aae72b8f8e..39dbb5f8e8a 100644 --- a/service/marketplacecommerceanalytics/api_client.go +++ b/service/marketplacecommerceanalytics/api_client.go @@ -4,6 +4,7 @@ package marketplacecommerceanalytics import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/marketplaceentitlementservice/api_client.go b/service/marketplaceentitlementservice/api_client.go index f54a8736769..45dfe30272d 100644 --- a/service/marketplaceentitlementservice/api_client.go +++ b/service/marketplaceentitlementservice/api_client.go @@ -4,6 +4,7 @@ package marketplaceentitlementservice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/marketplacemetering/api_client.go b/service/marketplacemetering/api_client.go index 8b2ffd674a2..d2e954170ae 100644 --- a/service/marketplacemetering/api_client.go +++ b/service/marketplacemetering/api_client.go @@ -4,6 +4,7 @@ package marketplacemetering import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/mediaconnect/api_client.go b/service/mediaconnect/api_client.go index 469d3d561e3..06a2b409037 100644 --- a/service/mediaconnect/api_client.go +++ b/service/mediaconnect/api_client.go @@ -4,6 +4,7 @@ package mediaconnect import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mediaconvert/api_client.go b/service/mediaconvert/api_client.go index c5866aebf42..eba87b4352e 100644 --- a/service/mediaconvert/api_client.go +++ b/service/mediaconvert/api_client.go @@ -4,6 +4,7 @@ package mediaconvert import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/medialive/api_client.go b/service/medialive/api_client.go index ae4ac05a25c..c1bc10750bf 100644 --- a/service/medialive/api_client.go +++ b/service/medialive/api_client.go @@ -4,6 +4,7 @@ package medialive import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mediapackage/api_client.go b/service/mediapackage/api_client.go index 5ad4db7d2e2..b9fd50269e9 100644 --- a/service/mediapackage/api_client.go +++ b/service/mediapackage/api_client.go @@ -4,6 +4,7 @@ package mediapackage import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mediapackagevod/api_client.go b/service/mediapackagevod/api_client.go index 5b04c2ee383..a3d79a0e8e5 100644 --- a/service/mediapackagevod/api_client.go +++ b/service/mediapackagevod/api_client.go @@ -4,6 +4,7 @@ package mediapackagevod import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mediastore/api_client.go b/service/mediastore/api_client.go index 1f56c9fa808..0d5b3611e99 100644 --- a/service/mediastore/api_client.go +++ b/service/mediastore/api_client.go @@ -4,6 +4,7 @@ package mediastore import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/mediastoredata/api_client.go b/service/mediastoredata/api_client.go index 3601f31b08a..03d31c46ee6 100644 --- a/service/mediastoredata/api_client.go +++ b/service/mediastoredata/api_client.go @@ -4,6 +4,7 @@ package mediastoredata import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mediatailor/api_client.go b/service/mediatailor/api_client.go index eb6db7cdce2..143d7fe76ee 100644 --- a/service/mediatailor/api_client.go +++ b/service/mediatailor/api_client.go @@ -4,6 +4,7 @@ package mediatailor import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/migrationhub/api_client.go b/service/migrationhub/api_client.go index 1782990285a..822975cfb0e 100644 --- a/service/migrationhub/api_client.go +++ b/service/migrationhub/api_client.go @@ -4,6 +4,7 @@ package migrationhub import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/migrationhubconfig/api_client.go b/service/migrationhubconfig/api_client.go index 9be0688cc44..0b3322c5793 100644 --- a/service/migrationhubconfig/api_client.go +++ b/service/migrationhubconfig/api_client.go @@ -4,6 +4,7 @@ package migrationhubconfig import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/mobile/api_client.go b/service/mobile/api_client.go index 65c099eec60..6091490d6ed 100644 --- a/service/mobile/api_client.go +++ b/service/mobile/api_client.go @@ -4,6 +4,7 @@ package mobile import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mobileanalytics/api_client.go b/service/mobileanalytics/api_client.go index 151cb55c669..ca417642805 100644 --- a/service/mobileanalytics/api_client.go +++ b/service/mobileanalytics/api_client.go @@ -4,6 +4,7 @@ package mobileanalytics import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mq/api_client.go b/service/mq/api_client.go index af4c84805ba..9df3b016569 100644 --- a/service/mq/api_client.go +++ b/service/mq/api_client.go @@ -4,6 +4,7 @@ package mq import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/mturk/api_client.go b/service/mturk/api_client.go index f3f6c3380d1..78e7f4b9446 100644 --- a/service/mturk/api_client.go +++ b/service/mturk/api_client.go @@ -4,6 +4,7 @@ package mturk import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/neptune/api_client.go b/service/neptune/api_client.go index 63498b6a7df..f3275c72ded 100644 --- a/service/neptune/api_client.go +++ b/service/neptune/api_client.go @@ -4,6 +4,7 @@ package neptune import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/networkmanager/api_client.go b/service/networkmanager/api_client.go index 54484d1a3ff..61fc9d7c6e9 100644 --- a/service/networkmanager/api_client.go +++ b/service/networkmanager/api_client.go @@ -4,6 +4,7 @@ package networkmanager import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/opsworks/api_client.go b/service/opsworks/api_client.go index fb087a73056..bac5f8640ba 100644 --- a/service/opsworks/api_client.go +++ b/service/opsworks/api_client.go @@ -4,6 +4,7 @@ package opsworks import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/opsworkscm/api_client.go b/service/opsworkscm/api_client.go index 935e0a6a9cc..a29f5110259 100644 --- a/service/opsworkscm/api_client.go +++ b/service/opsworkscm/api_client.go @@ -4,6 +4,7 @@ package opsworkscm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/organizations/api_client.go b/service/organizations/api_client.go index e3451d96036..891e3a19feb 100644 --- a/service/organizations/api_client.go +++ b/service/organizations/api_client.go @@ -4,6 +4,7 @@ package organizations import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/outposts/api_client.go b/service/outposts/api_client.go index eedc3177953..7319f1f86c6 100644 --- a/service/outposts/api_client.go +++ b/service/outposts/api_client.go @@ -4,6 +4,7 @@ package outposts import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/personalize/api_client.go b/service/personalize/api_client.go index 17aaaf0499d..99aa875f48f 100644 --- a/service/personalize/api_client.go +++ b/service/personalize/api_client.go @@ -4,6 +4,7 @@ package personalize import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/personalizeevents/api_client.go b/service/personalizeevents/api_client.go index c84aad5b4da..089d496e95e 100644 --- a/service/personalizeevents/api_client.go +++ b/service/personalizeevents/api_client.go @@ -4,6 +4,7 @@ package personalizeevents import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/personalizeruntime/api_client.go b/service/personalizeruntime/api_client.go index a47dbee6010..25c40bab6db 100644 --- a/service/personalizeruntime/api_client.go +++ b/service/personalizeruntime/api_client.go @@ -4,6 +4,7 @@ package personalizeruntime import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/pi/api_client.go b/service/pi/api_client.go index 7a0cac524a5..b96aec302ff 100644 --- a/service/pi/api_client.go +++ b/service/pi/api_client.go @@ -4,6 +4,7 @@ package pi import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/pinpoint/api_client.go b/service/pinpoint/api_client.go index 28f4f608582..2832707414d 100644 --- a/service/pinpoint/api_client.go +++ b/service/pinpoint/api_client.go @@ -4,6 +4,7 @@ package pinpoint import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/pinpointemail/api_client.go b/service/pinpointemail/api_client.go index 7c54c9569b0..d3535f11bb6 100644 --- a/service/pinpointemail/api_client.go +++ b/service/pinpointemail/api_client.go @@ -4,6 +4,7 @@ package pinpointemail import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/pinpointsmsvoice/api_client.go b/service/pinpointsmsvoice/api_client.go index fc4442cd0dd..81a3539e613 100644 --- a/service/pinpointsmsvoice/api_client.go +++ b/service/pinpointsmsvoice/api_client.go @@ -4,6 +4,7 @@ package pinpointsmsvoice import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/polly/api_client.go b/service/polly/api_client.go index 2eabc43a89b..24912b118d1 100644 --- a/service/polly/api_client.go +++ b/service/polly/api_client.go @@ -4,6 +4,7 @@ package polly import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/pricing/api_client.go b/service/pricing/api_client.go index 3830d92610d..b5e2b64708a 100644 --- a/service/pricing/api_client.go +++ b/service/pricing/api_client.go @@ -4,6 +4,7 @@ package pricing import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/qldb/api_client.go b/service/qldb/api_client.go index f44d1d8afcc..da6f109d670 100644 --- a/service/qldb/api_client.go +++ b/service/qldb/api_client.go @@ -4,6 +4,7 @@ package qldb import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/qldbsession/api_client.go b/service/qldbsession/api_client.go index 3f7a916b4bd..f3149b37312 100644 --- a/service/qldbsession/api_client.go +++ b/service/qldbsession/api_client.go @@ -4,6 +4,7 @@ package qldbsession import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/quicksight/api_client.go b/service/quicksight/api_client.go index 2d6c879ff54..ecc0546eb1c 100644 --- a/service/quicksight/api_client.go +++ b/service/quicksight/api_client.go @@ -4,6 +4,7 @@ package quicksight import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/ram/api_client.go b/service/ram/api_client.go index b32f75658cf..c2f86e67f4b 100644 --- a/service/ram/api_client.go +++ b/service/ram/api_client.go @@ -4,6 +4,7 @@ package ram import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/rds/api_client.go b/service/rds/api_client.go index 5dd6807278b..73387581434 100644 --- a/service/rds/api_client.go +++ b/service/rds/api_client.go @@ -4,6 +4,7 @@ package rds import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/rdsdata/api_client.go b/service/rdsdata/api_client.go index 0779d4bdadf..2a54e6d5992 100644 --- a/service/rdsdata/api_client.go +++ b/service/rdsdata/api_client.go @@ -4,6 +4,7 @@ package rdsdata import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/redshift/api_client.go b/service/redshift/api_client.go index 745be132002..9894455437e 100644 --- a/service/redshift/api_client.go +++ b/service/redshift/api_client.go @@ -4,6 +4,7 @@ package redshift import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/rekognition/api_client.go b/service/rekognition/api_client.go index 368f1a7ad4c..1c8b0c66421 100644 --- a/service/rekognition/api_client.go +++ b/service/rekognition/api_client.go @@ -4,6 +4,7 @@ package rekognition import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/resourcegroups/api_client.go b/service/resourcegroups/api_client.go index 1a12b57165a..cc4bad563db 100644 --- a/service/resourcegroups/api_client.go +++ b/service/resourcegroups/api_client.go @@ -4,6 +4,7 @@ package resourcegroups import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/resourcegroupstaggingapi/api_client.go b/service/resourcegroupstaggingapi/api_client.go index 961cc79d9c3..37b44b259c1 100644 --- a/service/resourcegroupstaggingapi/api_client.go +++ b/service/resourcegroupstaggingapi/api_client.go @@ -4,6 +4,7 @@ package resourcegroupstaggingapi import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/robomaker/api_client.go b/service/robomaker/api_client.go index 83ff0c75874..21ee8a15056 100644 --- a/service/robomaker/api_client.go +++ b/service/robomaker/api_client.go @@ -4,6 +4,7 @@ package robomaker import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/route53/api_client.go b/service/route53/api_client.go index c8100fc803e..0b9e1134895 100644 --- a/service/route53/api_client.go +++ b/service/route53/api_client.go @@ -4,6 +4,7 @@ package route53 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restxml" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/service/route53/unmarshal_error_test.go b/service/route53/unmarshal_error_test.go index 8e925c404e9..1f728d1673c 100644 --- a/service/route53/unmarshal_error_test.go +++ b/service/route53/unmarshal_error_test.go @@ -3,6 +3,7 @@ package route53_test import ( "bytes" "context" + "errors" "io/ioutil" "net/http" "testing" @@ -116,18 +117,24 @@ but it already exists t.Fatal("returned error is not a RequestFailure") } - if batchErr, ok := err.(awserr.BatchedErrors); ok { - errs := batchErr.OrigErrs() - if e, a := 1, len(errs); e != a { - t.Errorf("expected %d, but received %d", e, a) - } - if e, a := "InvalidChangeBatch", errs[0].(awserr.Error).Code(); e != a { - t.Errorf("expected %s, but received %s", e, a) - } - if e, a := errorMessage, errs[0].(awserr.Error).Message(); e != a { - t.Errorf("expected %s, but received %s", e, a) - } - } else { - t.Fatal("returned error is not a BatchedErrors") + var be awserr.BatchedErrors + if !errors.As(err, &be) { + t.Fatalf("expect %T error, got %v", be, err) + } + + errs := be.Errs() + if e, a := 1, len(errs); e != a { + t.Errorf("expected %d, but received %d", e, a) + } + + var ee awserr.Error + if !errors.As(errs[0], &ee) { + t.Fatalf("expect %T error got %v", ee, errs[0]) + } + if e, a := "InvalidChangeBatch", ee.Code(); e != a { + t.Errorf("expected %s, but received %s", e, a) + } + if e, a := errorMessage, ee.Message(); e != a { + t.Errorf("expected %s, but received %s", e, a) } } diff --git a/service/route53domains/api_client.go b/service/route53domains/api_client.go index 5d006adf715..98b18907da4 100644 --- a/service/route53domains/api_client.go +++ b/service/route53domains/api_client.go @@ -4,6 +4,7 @@ package route53domains import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/route53resolver/api_client.go b/service/route53resolver/api_client.go index 099056c9010..95505074acf 100644 --- a/service/route53resolver/api_client.go +++ b/service/route53resolver/api_client.go @@ -4,6 +4,7 @@ package route53resolver import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/s3/api_client.go b/service/s3/api_client.go index 5e1c36672d1..18ee2784536 100644 --- a/service/s3/api_client.go +++ b/service/s3/api_client.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restxml" ) @@ -97,6 +98,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + if err := resolveClientConfig(svc, config.ConfigSources); err != nil { panic(fmt.Errorf("failed to resolve service configuration: %v", err)) } diff --git a/service/s3/s3crypto/decryption_client_test.go b/service/s3/s3crypto/decryption_client_test.go index 2b1f5fa0411..29cd27971a8 100644 --- a/service/s3/s3crypto/decryption_client_test.go +++ b/service/s3/s3crypto/decryption_client_test.go @@ -5,6 +5,7 @@ import ( "context" "encoding/base64" "encoding/hex" + "errors" "fmt" "io/ioutil" "net/http" @@ -13,7 +14,6 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/service/s3" @@ -240,11 +240,12 @@ func TestGetObjectWithContext(t *testing.T) { if err == nil { t.Fatalf("expected error, did not get one") } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expected error code %q, got %q", e, a) + + var rc *aws.RequestCanceledError + if !errors.As(err, &rc) { + t.Fatalf("expect %T error, got %v", rc, err) } - if e, a := "canceled", aerr.Message(); !strings.Contains(a, e) { - t.Errorf("expected error message to contain %q, but did not %q", e, a) + if e, a := "canceled", rc.Err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v to be in, %v", e, a) } } diff --git a/service/s3/s3crypto/encryption_client_test.go b/service/s3/s3crypto/encryption_client_test.go index c12d6154060..73d79bdffe9 100644 --- a/service/s3/s3crypto/encryption_client_test.go +++ b/service/s3/s3crypto/encryption_client_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/service/kms" @@ -103,11 +102,12 @@ func TestPutObjectWithContext(t *testing.T) { if err == nil { t.Fatalf("expected error, did not get one") } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expected error code %q, got %q", e, a) + + var rc *aws.RequestCanceledError + if !errors.As(err, &rc) { + t.Fatalf("expect %T error, got %v", rc, err) } - if e, a := "canceled", aerr.Message(); !strings.Contains(a, e) { - t.Errorf("expected error message to contain %q, but did not %q", e, a) + if e, a := "canceled", rc.Err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v to be in, %v", e, a) } } diff --git a/service/s3/s3manager/download.go b/service/s3/s3manager/download.go index 749fb086a82..5c063ecb0f7 100644 --- a/service/s3/s3manager/download.go +++ b/service/s3/s3manager/download.go @@ -205,7 +205,7 @@ func (d Downloader) DownloadWithContext(ctx context.Context, w io.WriterAt, inpu impl.cfg.RequestOptions = append(impl.cfg.RequestOptions, request.WithAppendUserAgent("S3Manager")) if d.Retryer != nil { - impl.partBodyMaxRetries = d.Retryer.MaxRetries() + impl.partBodyMaxRetries = d.Retryer.MaxAttempts() - 1 } impl.totalBytes = -1 diff --git a/service/s3/s3manager/download_test.go b/service/s3/s3manager/download_test.go index e29be063e90..0bc6c50fb33 100644 --- a/service/s3/s3manager/download_test.go +++ b/service/s3/s3manager/download_test.go @@ -2,6 +2,7 @@ package s3manager_test import ( "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -17,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/internal/awstesting" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/internal/sdkio" @@ -166,8 +168,8 @@ func dlLoggingSvcWithErrReader(cases []testErrReader) (*s3.Client, *[]string) { case 0: // zero retries expected cfg.Retryer = aws.NoOpRetryer{} default: - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = len(cases) - 1 + cfg.Retryer = retry.NewStandard(func(s *retry.StandardOptions) { + s.MaxAttempts = len(cases) }) } @@ -544,11 +546,13 @@ func TestDownloadWithContextCanceled(t *testing.T) { if err == nil { t.Fatalf("expected error, did not get one") } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expected error code %q, got %q", e, a) + + var rc *aws.RequestCanceledError + if !errors.As(err, &rc) { + t.Fatalf("expect %T error, got %v", rc, err) } - if e, a := "canceled", aerr.Message(); !strings.Contains(a, e) { + + if e, a := "canceled", rc.Err.Error(); !strings.Contains(a, e) { t.Errorf("expected error message to contain %q, but did not %q", e, a) } } @@ -618,7 +622,6 @@ func TestDownload_WithFailure(t *testing.T) { Body: ioutil.NopCloser(&bytes.Buffer{}), } r.Error = awserr.New("ConnectionError", "some connection error", nil) - r.Retryable = aws.Bool(false) }) start := time.Now() diff --git a/service/s3/s3manager/upload.go b/service/s3/s3manager/upload.go index 1b5c4b7c11c..e9a11ddbd42 100644 --- a/service/s3/s3manager/upload.go +++ b/service/s3/s3manager/upload.go @@ -3,6 +3,7 @@ package s3manager import ( "bytes" "context" + "errors" "fmt" "io" "sort" @@ -76,18 +77,10 @@ type multiUploadError struct { // Error returns the string representation of the error. // -// See apierr.BaseError ErrorWithExtra for output format -// // Satisfies the error interface. func (m multiUploadError) Error() string { extra := fmt.Sprintf("upload id: %s", m.uploadID) - return awserr.SprintError(m.Code(), m.Message(), extra, m.OrigErr()) -} - -// String returns the string representation of the error. -// Alias for Error to satisfy the stringer interface. -func (m multiUploadError) String() string { - return m.Error() + return awserr.SprintError(m.Code(), m.Message(), extra, m.Unwrap()) } // UploadID returns the id of the S3 upload which failed. @@ -95,6 +88,10 @@ func (m multiUploadError) UploadID() string { return m.uploadID } +func (m multiUploadError) Unwrap() error { + return errors.Unwrap(m.awsError) +} + // UploadOutput represents a response from the Upload() call. type UploadOutput struct { // The URL where the object was uploaded to. diff --git a/service/s3/s3manager/upload_test.go b/service/s3/s3manager/upload_test.go index 43a79276e08..45bc7a4270a 100644 --- a/service/s3/s3manager/upload_test.go +++ b/service/s3/s3manager/upload_test.go @@ -2,6 +2,7 @@ package s3manager_test import ( "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -300,9 +301,8 @@ func TestUploadReaderReturnsNegative(t *testing.T) { t.Error("Expected error, but received none") } - aerr := err.(awserr.Error) - if aerr.OrigErr() != io.ErrUnexpectedEOF { - t.Fatalf("expected %s. Got %s", io.ErrUnexpectedEOF, aerr.OrigErr()) + if e, a := io.ErrUnexpectedEOF, err; !errors.Is(a, e) { + t.Fatalf("expect %v error, got %v", e, a) } } @@ -540,14 +540,22 @@ func TestUploadOrderReadFail1(t *testing.T) { Body: &failreader{times: 1}, }) - if e, a := "ReadRequestBody", err.(awserr.Error).Code(); e != a { - t.Errorf("Expected %q, but received %q", e, a) + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) } - if e, a := err.(awserr.Error).OrigErr().Error(), "random failure"; e != a { - t.Errorf("Expected %q, but received %q", e, a) + if e, a := "ReadRequestBody", aerr.Code(); e != a { + t.Errorf("expect %q code, got %q", e, a) } + origErr := errors.Unwrap(aerr) + if origErr == nil { + t.Fatalf("expect wrapped error, was none") + } + if e, a := "random failure", origErr.Error(); !strings.Contains(a, e) { + t.Errorf("expected %q, but received %q", e, a) + } if e, a := []string{}, *ops; !reflect.DeepEqual(e, a) { t.Errorf("Expected %v, but received %v", e, a) } @@ -564,16 +572,25 @@ func TestUploadOrderReadFail2(t *testing.T) { Body: &failreader{times: 2}, }) - if e, a := "MultipartUpload", err.(awserr.Error).Code(); e != a { + var aerr awserr.Error + if !errors.As(err, &aerr) { + t.Fatalf("expect %T error, got %v", aerr, err) + } + + if e, a := "MultipartUpload", aerr.Code(); e != a { t.Errorf("Expected %q, but received %q", e, a) } - if e, a := "ReadRequestBody", err.(awserr.Error).OrigErr().(awserr.Error).Code(); e != a { + origErr := errors.Unwrap(aerr) + if origErr == nil { + t.Fatalf("expect wrapped error, was none") + } + if e, a := "ReadRequestBody", origErr.(awserr.Error).Code(); e != a { t.Errorf("Expected %q, but received %q", e, a) } - if errStr := err.(awserr.Error).OrigErr().Error(); !strings.Contains(errStr, "random failure") { - t.Errorf("Expected error to contains 'random failure', but was %q", errStr) + if e, a := "random failure", origErr.Error(); !strings.Contains(a, e) { + t.Errorf("expect %q error, got %q", e, a) } if e, a := []string{"CreateMultipartUpload", "AbortMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) { @@ -724,12 +741,16 @@ func TestUploadOrderMultiBufferedReaderExceedTotalParts(t *testing.T) { t.Errorf("Expected %q, but received %q", e, a) } - if e, a := "TotalPartsExceeded", aerr.OrigErr().(awserr.Error).Code(); e != a { - t.Errorf("Expected %q, but received %q", e, a) + origErr := errors.Unwrap(aerr) + if origErr == nil { + t.Fatalf("expect wrapped error, was none") + } + if e, a := "TotalPartsExceeded", origErr.(awserr.Error).Code(); e != a { + t.Errorf("expect %q, but received %q", e, a) } - if !strings.Contains(aerr.Error(), "configured MaxUploadParts (2)") { - t.Errorf("Expected error to contain 'configured MaxUploadParts (2)', but receievd %q", aerr.Error()) + if e, a := "configured MaxUploadParts (2)", aerr.Error(); !strings.Contains(a, e) { + t.Errorf("expect %q, but received %q", e, a) } } @@ -1026,12 +1047,13 @@ func TestUploadWithContextCanceled(t *testing.T) { if err == nil { t.Fatalf("expected error, did not get one") } - aerr := err.(awserr.Error) - if e, a := aws.ErrCodeRequestCanceled, aerr.Code(); e != a { - t.Errorf("expected error code %q, got %q", e, a) + + var rc *aws.RequestCanceledError + if !errors.As(err, &rc) { + t.Fatalf("expect %T error, got %v", rc, err) } - if e, a := "canceled", aerr.Message(); !strings.Contains(a, e) { - t.Errorf("expected error message to contain %q, but did not %q", e, a) + if e, a := "canceled", rc.Err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v to be in, %v", e, a) } } diff --git a/service/s3/unmarshal_error.go b/service/s3/unmarshal_error.go index 4226e1c3628..bf0f8df5e07 100644 --- a/service/s3/unmarshal_error.go +++ b/service/s3/unmarshal_error.go @@ -2,6 +2,7 @@ package s3 import ( "encoding/xml" + "errors" "fmt" "io" "io/ioutil" @@ -92,11 +93,14 @@ type requestFailure struct { func (r requestFailure) Error() string { extra := fmt.Sprintf("status code: %d, request id: %s, host id: %s", r.StatusCode(), r.RequestID(), r.hostID) - return awserr.SprintError(r.Code(), r.Message(), extra, r.OrigErr()) -} -func (r requestFailure) String() string { - return r.Error() + + return awserr.SprintError(r.Code(), r.Message(), extra, r.Unwrap()) } + func (r requestFailure) HostID() string { return r.hostID } + +func (r requestFailure) Unwrap() error { + return errors.Unwrap(r.RequestFailure) +} diff --git a/service/s3/unmarshal_error_test.go b/service/s3/unmarshal_error_test.go index d3b4b3bebd2..1981269b7cc 100644 --- a/service/s3/unmarshal_error_test.go +++ b/service/s3/unmarshal_error_test.go @@ -3,9 +3,11 @@ package s3_test import ( "bytes" "context" + "errors" "fmt" "io/ioutil" "net/http" + "strconv" "strings" "testing" @@ -143,36 +145,44 @@ var testUnmarshalCases = []testErrorCase{ func TestUnmarshalError(t *testing.T) { for i, c := range testUnmarshalCases { - s := s3.New(unit.Config()) - s.Handlers.Send.Clear() - s.Handlers.Send.PushBack(func(r *request.Request) { - r.HTTPResponse = c.RespFn() - if !c.WithoutStatusMsg { - r.HTTPResponse.Status = fmt.Sprintf("%d%s", - r.HTTPResponse.StatusCode, - http.StatusText(r.HTTPResponse.StatusCode)) + t.Run(strconv.Itoa(i), func(t *testing.T) { + s := s3.New(unit.Config()) + s.Handlers.Send.Clear() + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = c.RespFn() + if !c.WithoutStatusMsg { + r.HTTPResponse.Status = fmt.Sprintf("%d%s", + r.HTTPResponse.StatusCode, + http.StatusText(r.HTTPResponse.StatusCode)) + } + }) + req := s.PutBucketAclRequest(&s3.PutBucketAclInput{ + Bucket: aws.String("bucket"), ACL: s3.BucketCannedACLPublicRead, + }) + _, err := req.Send(context.Background()) + + if err == nil { + t.Fatalf("expected error, got nil") } - }) - req := s.PutBucketAclRequest(&s3.PutBucketAclInput{ - Bucket: aws.String("bucket"), ACL: s3.BucketCannedACLPublicRead, - }) - _, err := req.Send(context.Background()) - if err == nil { - t.Fatalf("%d, expected error, got nil", i) - } - if e, a := c.Code, err.(awserr.Error).Code(); e != a { - t.Errorf("%d, Code: expect %s, got %s", i, e, a) - } - if e, a := c.Msg, err.(awserr.Error).Message(); e != a { - t.Errorf("%d, Message: expect %s, got %s", i, e, a) - } - if e, a := c.ReqID, err.(awserr.RequestFailure).RequestID(); e != a { - t.Errorf("%d, RequestID: expect %s, got %s", i, e, a) - } - if e, a := c.HostID, err.(s3.RequestFailure).HostID(); e != a { - t.Errorf("%d, HostID: expect %s, got %s", i, e, a) - } + var v s3.RequestFailure + if !errors.As(err, &v) { + t.Fatalf("expect an API error, got %v", err) + } + + if e, a := c.Code, v.Code(); e != a { + t.Errorf("Code: expect %s, got %s", e, a) + } + if e, a := c.Msg, v.Message(); e != a { + t.Errorf("Message: expect %s, got %s", e, a) + } + if e, a := c.ReqID, v.RequestID(); e != a { + t.Errorf("RequestID: expect %s, got %s", e, a) + } + if e, a := c.HostID, v.HostID(); e != a { + t.Errorf("HostID: expect %s, got %s", e, a) + } + }) } } diff --git a/service/s3control/api_client.go b/service/s3control/api_client.go index fc9fb3aac31..2f706c4d0c7 100644 --- a/service/s3control/api_client.go +++ b/service/s3control/api_client.go @@ -4,6 +4,7 @@ package s3control import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restxml" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restxml.BuildHandler) diff --git a/service/sagemaker/api_client.go b/service/sagemaker/api_client.go index c2bcd49245a..7bf0d1ee1d7 100644 --- a/service/sagemaker/api_client.go +++ b/service/sagemaker/api_client.go @@ -4,6 +4,7 @@ package sagemaker import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/sagemakera2iruntime/api_client.go b/service/sagemakera2iruntime/api_client.go index 3c6851ee408..c584d3d6c06 100644 --- a/service/sagemakera2iruntime/api_client.go +++ b/service/sagemakera2iruntime/api_client.go @@ -4,6 +4,7 @@ package sagemakera2iruntime import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/sagemakerruntime/api_client.go b/service/sagemakerruntime/api_client.go index 95ab51ce5f6..9c22a81577d 100644 --- a/service/sagemakerruntime/api_client.go +++ b/service/sagemakerruntime/api_client.go @@ -4,6 +4,7 @@ package sagemakerruntime import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/savingsplans/api_client.go b/service/savingsplans/api_client.go index 11bb9fd8479..10fd2d6006e 100644 --- a/service/savingsplans/api_client.go +++ b/service/savingsplans/api_client.go @@ -4,6 +4,7 @@ package savingsplans import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/schemas/api_client.go b/service/schemas/api_client.go index bd4c2fb8e9a..a9a6ac699e3 100644 --- a/service/schemas/api_client.go +++ b/service/schemas/api_client.go @@ -4,6 +4,7 @@ package schemas import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/secretsmanager/api_client.go b/service/secretsmanager/api_client.go index 4202ebd6d6b..1e49e560e9d 100644 --- a/service/secretsmanager/api_client.go +++ b/service/secretsmanager/api_client.go @@ -4,6 +4,7 @@ package secretsmanager import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/securityhub/api_client.go b/service/securityhub/api_client.go index e2f139066b7..1951e396ff6 100644 --- a/service/securityhub/api_client.go +++ b/service/securityhub/api_client.go @@ -4,6 +4,7 @@ package securityhub import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/serverlessapplicationrepository/api_client.go b/service/serverlessapplicationrepository/api_client.go index a47e88ee733..e7dc2a77d10 100644 --- a/service/serverlessapplicationrepository/api_client.go +++ b/service/serverlessapplicationrepository/api_client.go @@ -4,6 +4,7 @@ package serverlessapplicationrepository import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/servicecatalog/api_client.go b/service/servicecatalog/api_client.go index 844839e535a..76fd7e2a502 100644 --- a/service/servicecatalog/api_client.go +++ b/service/servicecatalog/api_client.go @@ -4,6 +4,7 @@ package servicecatalog import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/servicediscovery/api_client.go b/service/servicediscovery/api_client.go index e0d74b152e0..832fbc7fbf6 100644 --- a/service/servicediscovery/api_client.go +++ b/service/servicediscovery/api_client.go @@ -4,6 +4,7 @@ package servicediscovery import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/servicequotas/api_client.go b/service/servicequotas/api_client.go index 374593f3435..a5cf94b9916 100644 --- a/service/servicequotas/api_client.go +++ b/service/servicequotas/api_client.go @@ -4,6 +4,7 @@ package servicequotas import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/ses/api_client.go b/service/ses/api_client.go index 19dbeab3f29..da8f0c6f3be 100644 --- a/service/ses/api_client.go +++ b/service/ses/api_client.go @@ -4,6 +4,7 @@ package ses import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/sesv2/api_client.go b/service/sesv2/api_client.go index 172a92fa05a..74d5b46e8f9 100644 --- a/service/sesv2/api_client.go +++ b/service/sesv2/api_client.go @@ -4,6 +4,7 @@ package sesv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/sfn/api_client.go b/service/sfn/api_client.go index 173e61f329a..d9a92401802 100644 --- a/service/sfn/api_client.go +++ b/service/sfn/api_client.go @@ -4,6 +4,7 @@ package sfn import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/shield/api_client.go b/service/shield/api_client.go index 9cf2cc80c16..4331c9003ef 100644 --- a/service/shield/api_client.go +++ b/service/shield/api_client.go @@ -4,6 +4,7 @@ package shield import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/signer/api_client.go b/service/signer/api_client.go index 2140827fb4e..90367aa0370 100644 --- a/service/signer/api_client.go +++ b/service/signer/api_client.go @@ -4,6 +4,7 @@ package signer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/simpledb/api_client.go b/service/simpledb/api_client.go index 50a9530ac53..f294dbf8a27 100644 --- a/service/simpledb/api_client.go +++ b/service/simpledb/api_client.go @@ -5,6 +5,7 @@ package simpledb import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v2" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -51,6 +52,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v2.SignRequestHandler) svc.Handlers.Sign.PushBackNamed(defaults.BuildContentLengthHandler) diff --git a/service/simpledb/unmarshall_error_test.go b/service/simpledb/unmarshall_error_test.go index afacaa155ab..11fc041e0e3 100644 --- a/service/simpledb/unmarshall_error_test.go +++ b/service/simpledb/unmarshall_error_test.go @@ -3,12 +3,12 @@ package simpledb_test import ( "bytes" "context" + "errors" "io/ioutil" "net/http" "testing" "github.com/aws/aws-sdk-go-v2/aws" - request "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/service/simpledb" @@ -31,7 +31,7 @@ func TestStatusCodeError(t *testing.T) { for _, test := range statusCodeErrorTests { s := simpledb.New(unit.Config()) s.Handlers.Send.Clear() - s.Handlers.Send.PushBack(func(r *request.Request) { + s.Handlers.Send.PushBack(func(r *aws.Request) { body := ioutil.NopCloser(bytes.NewReader([]byte{})) r.HTTPResponse = &http.Response{ ContentLength: 0, @@ -48,10 +48,15 @@ func TestStatusCodeError(t *testing.T) { if err == nil { t.Fatalf("expect error, got nil") } - if e, a := test.code, err.(awserr.Error).Code(); e != a { + + var v awserr.Error + if !errors.As(err, &v) { + t.Fatalf("expect API error, got %v", err) + } + if e, a := test.code, v.Code(); e != a { t.Errorf("expect %v, got %v", e, a) } - if e, a := test.message, err.(awserr.Error).Message(); e != a { + if e, a := test.message, v.Message(); e != a { t.Errorf("expect %v, got %v", e, a) } } @@ -103,7 +108,7 @@ func TestResponseError(t *testing.T) { for _, test := range responseErrorTests { s := simpledb.New(unit.Config()) s.Handlers.Send.Clear() - s.Handlers.Send.PushBack(func(r *request.Request) { + s.Handlers.Send.PushBack(func(r *aws.Request) { xml := createXMLResponse(test.requestID, test.errors) body := ioutil.NopCloser(bytes.NewReader([]byte(xml))) r.HTTPResponse = &http.Response{ @@ -121,17 +126,26 @@ func TestResponseError(t *testing.T) { if err == nil { t.Fatalf("expect error, got none") } - if e, a := test.code, err.(awserr.Error).Code(); e != a { + + var v awserr.Error + if !errors.As(err, &v) { + t.Fatalf("expect awserr error, got %v", err) + } + if e, a := test.code, v.Code(); e != a { t.Errorf("expect %v, got %v", e, a) } - if e, a := test.message, err.(awserr.Error).Message(); e != a { + if e, a := test.message, v.Message(); e != a { t.Errorf("expect %v, got %v", e, a) } if len(test.errors) > 0 { - if e, a := test.requestID, err.(awserr.RequestFailure).RequestID(); e != a { + var vv awserr.RequestFailure + if !errors.As(err, &vv) { + t.Fatalf("expect RequestFailure error, got %v", err) + } + if e, a := test.requestID, vv.RequestID(); e != a { t.Errorf("expect %v, got %v", e, a) } - if e, a := test.scode, err.(awserr.RequestFailure).StatusCode(); e != a { + if e, a := test.scode, vv.StatusCode(); e != a { t.Errorf("expect %v, got %v", e, a) } } diff --git a/service/sms/api_client.go b/service/sms/api_client.go index 4527d8feb33..9155335989e 100644 --- a/service/sms/api_client.go +++ b/service/sms/api_client.go @@ -4,6 +4,7 @@ package sms import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/snowball/api_client.go b/service/snowball/api_client.go index 288453ef52a..3e359f96590 100644 --- a/service/snowball/api_client.go +++ b/service/snowball/api_client.go @@ -4,6 +4,7 @@ package snowball import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/sns/api_client.go b/service/sns/api_client.go index 36d4ef505c1..38e454f999a 100644 --- a/service/sns/api_client.go +++ b/service/sns/api_client.go @@ -4,6 +4,7 @@ package sns import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/sqs/api_client.go b/service/sqs/api_client.go index cd4ec0bc3e4..dbc76121e54 100644 --- a/service/sqs/api_client.go +++ b/service/sqs/api_client.go @@ -4,6 +4,7 @@ package sqs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -55,6 +56,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/sqs/checksums.go b/service/sqs/checksums.go index 79771be5da9..31e6143e9d3 100644 --- a/service/sqs/checksums.go +++ b/service/sqs/checksums.go @@ -6,9 +6,7 @@ import ( "fmt" "strings" - "github.com/aws/aws-sdk-go-v2/aws" request "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" ) var ( @@ -33,7 +31,10 @@ func verifySendMessage(r *request.Request) { out := r.Data.(*SendMessageOutput) err := checksumsMatch(in.MessageBody, out.MD5OfMessageBody) if err != nil { - setChecksumError(r, err.Error()) + r.Error = &InvalidChecksumError{ + Reason: "response checksum does not match sent", + Err: err, + } } } } @@ -57,7 +58,9 @@ func verifySendMessageBatch(r *request.Request) { } } if len(ids) > 0 { - setChecksumError(r, "invalid messages: %s", strings.Join(ids, ", ")) + r.Error = &InvalidChecksumError{ + Reason: fmt.Sprintf("invalid messages: %s", strings.Join(ids, ", ")), + } } } } @@ -83,7 +86,9 @@ func verifyReceiveMessage(r *request.Request) { } } if len(ids) > 0 { - setChecksumError(r, "invalid messages: %s", strings.Join(ids, ", ")) + r.Error = &InvalidChecksumError{ + Reason: fmt.Sprintf("invalid messages: %s", strings.Join(ids, ", ")), + } } } } @@ -104,7 +109,22 @@ func checksumsMatch(body, expectedMD5 *string) error { return nil } -func setChecksumError(r *request.Request, format string, args ...interface{}) { - r.Retryable = aws.Bool(true) - r.Error = awserr.New("InvalidChecksum", fmt.Sprintf(format, args...), nil) +// InvalidChecksumError provides the error type for invalid checksum errors. +type InvalidChecksumError struct { + Reason string + Err error +} + +// RetryableError decorates this error as retryable. +func (e *InvalidChecksumError) RetryableError() bool { return true } + +// Unwrap returns the underlying error if there was one. +func (e *InvalidChecksumError) Unwrap() error { return e.Err } + +func (e *InvalidChecksumError) Error() string { + var extra string + if e.Err != nil { + extra = ", " + e.Err.Error() + } + return fmt.Sprintf("checksum validation error, %v%s", e.Reason, extra) } diff --git a/service/sqs/checksums_test.go b/service/sqs/checksums_test.go index c35a89f41e2..249c80b4d26 100644 --- a/service/sqs/checksums_test.go +++ b/service/sqs/checksums_test.go @@ -3,6 +3,7 @@ package sqs_test import ( "bytes" "context" + "errors" "io/ioutil" "net/http" "strings" @@ -10,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" request "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/aws/awserr" "github.com/aws/aws-sdk-go-v2/aws/defaults" "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit" "github.com/aws/aws-sdk-go-v2/service/sqs" @@ -60,10 +60,12 @@ func TestSendMessageChecksumInvalid(t *testing.T) { t.Fatalf("expect error, got nil") } - if e, a := "InvalidChecksum", err.(awserr.Error).Code(); e != a { - t.Errorf("expect %v, got %v", e, a) + var ce *sqs.InvalidChecksumError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := err.(awserr.Error).Message(), "expected MD5 checksum '000', got '098f6bcd4621d373cade4e832627b4f6'"; !strings.Contains(a, e) { + expectReason := "expected MD5 checksum '000', got '098f6bcd4621d373cade4e832627b4f6'" + if e, a := expectReason, ce.Error(); !strings.Contains(a, e) { t.Errorf("expect %v to be in %v, was not", e, a) } } @@ -105,10 +107,12 @@ func TestSendMessageChecksumNoInput(t *testing.T) { t.Fatalf("expect error, got nil") } - if e, a := "InvalidChecksum", err.(awserr.Error).Code(); e != a { - t.Errorf("expect %v, got %v", e, a) + var ce *sqs.InvalidChecksumError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := err.(awserr.Error).Message(), "cannot compute checksum. missing body"; !strings.Contains(a, e) { + expectReason := "cannot compute checksum. missing body" + if e, a := expectReason, ce.Error(); !strings.Contains(a, e) { t.Errorf("expect %v to be in %v, was not", e, a) } } @@ -127,10 +131,12 @@ func TestSendMessageChecksumNoOutput(t *testing.T) { t.Fatalf("expect error, got nil") } - if e, a := "InvalidChecksum", err.(awserr.Error).Code(); e != a { - t.Errorf("expect %v, got %v", e, a) + var ce *sqs.InvalidChecksumError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := err.(awserr.Error).Message(), "cannot verify checksum. missing response MD5"; !strings.Contains(a, e) { + expectReason := "cannot verify checksum. missing response MD5" + if e, a := expectReason, ce.Error(); !strings.Contains(a, e) { t.Errorf("expect %v to be in %v, was not", e, a) } } @@ -177,10 +183,12 @@ func TestRecieveMessageChecksumInvalid(t *testing.T) { t.Fatalf("expect error, got nil") } - if e, a := "InvalidChecksum", err.(awserr.Error).Code(); e != a { - t.Errorf("expect %v, got %v", e, a) + var ce *sqs.InvalidChecksumError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := err.(awserr.Error).Message(), "invalid messages: 123, 456"; !strings.Contains(a, e) { + expectReason := "invalid messages: 123, 456" + if e, a := expectReason, ce.Error(); !strings.Contains(a, e) { t.Errorf("expect %v to be in %v, was not", e, a) } } @@ -267,10 +275,12 @@ func TestSendMessageBatchChecksumInvalid(t *testing.T) { t.Fatalf("expect error, got nil") } - if e, a := "InvalidChecksum", err.(awserr.Error).Code(); e != a { - t.Errorf("expect %v, got %v", e, a) + var ce *sqs.InvalidChecksumError + if !errors.As(err, &ce) { + t.Fatalf("expect %T error, got %v", ce, err) } - if e, a := err.(awserr.Error).Message(), "invalid messages: 456, 789"; !strings.Contains(a, e) { + expectReason := "invalid messages: 456, 789" + if e, a := expectReason, ce.Error(); !strings.Contains(a, e) { t.Errorf("expect %v to be in %v, was not", e, a) } } diff --git a/service/ssm/api_client.go b/service/ssm/api_client.go index 7587f4ea862..7f37f8f265a 100644 --- a/service/ssm/api_client.go +++ b/service/ssm/api_client.go @@ -4,6 +4,7 @@ package ssm import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/sso/api_client.go b/service/sso/api_client.go index 5b2913185cf..60669be3280 100644 --- a/service/sso/api_client.go +++ b/service/sso/api_client.go @@ -4,6 +4,7 @@ package sso import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/ssooidc/api_client.go b/service/ssooidc/api_client.go index ac66edbb6f2..7c37bed3d85 100644 --- a/service/ssooidc/api_client.go +++ b/service/ssooidc/api_client.go @@ -4,6 +4,7 @@ package ssooidc import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/storagegateway/api_client.go b/service/storagegateway/api_client.go index 5434d414dc6..d863f7fa29d 100644 --- a/service/storagegateway/api_client.go +++ b/service/storagegateway/api_client.go @@ -4,6 +4,7 @@ package storagegateway import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/sts/api_client.go b/service/sts/api_client.go index b3af5cfd20e..671753f6982 100644 --- a/service/sts/api_client.go +++ b/service/sts/api_client.go @@ -4,6 +4,7 @@ package sts import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/query" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(query.BuildHandler) diff --git a/service/sts/customizations.go b/service/sts/customizations.go index 06f47229df6..a0e6bc067a4 100644 --- a/service/sts/customizations.go +++ b/service/sts/customizations.go @@ -1,9 +1,11 @@ package sts -import "github.com/aws/aws-sdk-go-v2/aws" +import ( + "github.com/aws/aws-sdk-go-v2/aws/retry" +) func init() { - initRequest = func(c *Client, r *aws.Request) { - r.RetryErrorCodes = append(r.RetryErrorCodes, ErrCodeIDPCommunicationErrorException) + initClient = func(c *Client) { + c.Retryer = retry.AddWithErrorCodes(c.Retryer, ErrCodeIDPCommunicationErrorException) } } diff --git a/service/sts/customizations_test.go b/service/sts/customizations_test.go index 6e57dfcc2ea..3a8340e0644 100644 --- a/service/sts/customizations_test.go +++ b/service/sts/customizations_test.go @@ -58,9 +58,6 @@ func TestUnsignedRequest_AssumeRoleWithWebIdentity(t *testing.T) { func TestSTSCustomRetryErrorCodes(t *testing.T) { cfg := unit.Config() - cfg.Retryer = aws.NewDefaultRetryer(func(d *aws.DefaultRetryer) { - d.NumMaxRetries = 1 - }) svc := sts.New(cfg) svc.Handlers.Validate.Clear() diff --git a/service/support/api_client.go b/service/support/api_client.go index b617d48160d..5ebcba21214 100644 --- a/service/support/api_client.go +++ b/service/support/api_client.go @@ -4,6 +4,7 @@ package support import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/swf/api_client.go b/service/swf/api_client.go index 186ce76a311..76e6d495a11 100644 --- a/service/swf/api_client.go +++ b/service/swf/api_client.go @@ -4,6 +4,7 @@ package swf import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/textract/api_client.go b/service/textract/api_client.go index faa6e2b0898..d7caae69662 100644 --- a/service/textract/api_client.go +++ b/service/textract/api_client.go @@ -4,6 +4,7 @@ package textract import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/transcribe/api_client.go b/service/transcribe/api_client.go index 73883267ccd..82a1d6e3478 100644 --- a/service/transcribe/api_client.go +++ b/service/transcribe/api_client.go @@ -4,6 +4,7 @@ package transcribe import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/transfer/api_client.go b/service/transfer/api_client.go index 65c2b6f26b9..a2608805cfe 100644 --- a/service/transfer/api_client.go +++ b/service/transfer/api_client.go @@ -4,6 +4,7 @@ package transfer import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/translate/api_client.go b/service/translate/api_client.go index 226cb8a4e8b..f9482115907 100644 --- a/service/translate/api_client.go +++ b/service/translate/api_client.go @@ -4,6 +4,7 @@ package translate import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/waf/api_client.go b/service/waf/api_client.go index 7027ea11215..56315f2cebf 100644 --- a/service/waf/api_client.go +++ b/service/waf/api_client.go @@ -4,6 +4,7 @@ package waf import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/wafregional/api_client.go b/service/wafregional/api_client.go index a4ff03ee847..ec48aaeaec5 100644 --- a/service/wafregional/api_client.go +++ b/service/wafregional/api_client.go @@ -4,6 +4,7 @@ package wafregional import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/wafv2/api_client.go b/service/wafv2/api_client.go index be5eefcbb14..2c5414438fb 100644 --- a/service/wafv2/api_client.go +++ b/service/wafv2/api_client.go @@ -4,6 +4,7 @@ package wafv2 import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/workdocs/api_client.go b/service/workdocs/api_client.go index 6cd4022ff24..c1e24e106fd 100644 --- a/service/workdocs/api_client.go +++ b/service/workdocs/api_client.go @@ -4,6 +4,7 @@ package workdocs import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/worklink/api_client.go b/service/worklink/api_client.go index 9f35fd33009..1da627a9bc3 100644 --- a/service/worklink/api_client.go +++ b/service/worklink/api_client.go @@ -4,6 +4,7 @@ package worklink import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/workmail/api_client.go b/service/workmail/api_client.go index e77cb739e9d..ed5d5f4e734 100644 --- a/service/workmail/api_client.go +++ b/service/workmail/api_client.go @@ -4,6 +4,7 @@ package workmail import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/workmailmessageflow/api_client.go b/service/workmailmessageflow/api_client.go index 65db5b6f6a3..e67eb5012f5 100644 --- a/service/workmailmessageflow/api_client.go +++ b/service/workmailmessageflow/api_client.go @@ -4,6 +4,7 @@ package workmailmessageflow import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler) diff --git a/service/workspaces/api_client.go b/service/workspaces/api_client.go index 2dacdc25a06..ce0a2d4c82f 100644 --- a/service/workspaces/api_client.go +++ b/service/workspaces/api_client.go @@ -4,6 +4,7 @@ package workspaces import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/jsonrpc" ) @@ -52,6 +53,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler) diff --git a/service/xray/api_client.go b/service/xray/api_client.go index 2cf5a1a0c40..bcc028dbba5 100644 --- a/service/xray/api_client.go +++ b/service/xray/api_client.go @@ -4,6 +4,7 @@ package xray import ( "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/private/protocol/restjson" ) @@ -50,6 +51,10 @@ func New(config aws.Config) *Client { ), } + if config.Retryer == nil { + svc.Retryer = retry.NewStandard() + } + // Handlers svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) svc.Handlers.Build.PushBackNamed(restjson.BuildHandler)