retryer.go

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