Documentation
¶
Overview ¶
Package retry implements retry logic for HTTP clients.
The Client type can be used directly and instantiated with NewClient. This function returns nil if the Config is configured for no retries.
The preferred way to use this package is by creating a middleware constructor with New:
ctor := New(Config{
Retries: 2,
Interval: 10 * time.Second,
})
c := ctor(&http.Client{
// setup the client
})
Exponential backoff with jitter is also supported. For example:
ctor := New(Config{
Retries: 2,
Interval: 10 * time.Second,
Multiplier: 2.0,
Jitter: 0.2,
})
The basic formula for each time to wait before the next retry, in terms of Config fields, is:
Interval * (Multiplier^n) * randBetween[1-Jitter,1+Jitter]
where n is the 0-based retry.
See the documentation for the Config type for more details.
Index ¶
Constants ¶
const ( // DefaultInterval is used when Config.Interval is nonpositive DefaultInterval time.Duration = 5 * time.Second )
Variables ¶
This section is empty.
Functions ¶
func DefaultCheck ¶
DefaultCheck is the Check predicate used if none is supplied.
This default implementation returns true under the following conditions:
- The response is not nil and the status code is one of: http.StatusRequestTimeout http.StatusTooManyRequests http.StatusGatewayTimeout
- The error is not nil and: supplies a "Temporary() bool" method that returns true (including any wrapped errors)
An important consequence of honoring the Temporary() method on errors is that transient network errors will be retried. One important example of this are DNS errors that are marked as temporary.
In all other cases, this default function returns false. Importantly, this means that context.DeadlineExceeded and context.Canceled are not retryable errors when using this check function.
func DefaultTimer ¶
DefaultTimer is the default Timer implementation. It simply delegates to time.NewTimer.
func New ¶
func New(cfg Config) client.Constructor
New creates a middleware constructor that decorates an HTTP client for retries. If cfg.Retries is nonpositive, the returned constructor does no decoration. This function is the primary and recommended way to implement HTTP client retry behavior.
The returned constructor will decorate http.DefaultClient if passed a nil client.
Types ¶
type Check ¶
Check is a predicate type used to determine if a result from http.Client.Do should be retried. Implementations should only return true if it is reasonable to retry the request. Examples of retryable situations are gateway timeouts and 429 (too many requests) responses.
For any HTTP transaction that is considered a success, implementations should return false to halt further retries.
For any HTTP transaction that failed but that shouldn't be retried, implementations should return false. An example of this is an HTTP status of 400, since that indicates that no further use of that request will succeed.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an httpaux.Client that retries HTTP transactions. The middleware returned by New uses this type to perform retries.
func NewClient ¶
NewClient constructs a Client from a configuration. If cfg.Retries is nonpositive, this function returns nil.
The next instance is used to actually execute HTTP transactions. If next is nil, http.DefaultClient is used.
This function is a low-level way to instantiate a client. Most users will instead create a middleware with New. This function can be used for more detailed usage.
func (*Client) Do ¶
Do takes in an original *http.Request and makes an initial attempt plus a maximum number of retries in order to satisfy the request.
IMPORTANT: This method can return both a non-nil response and a non-nil error. To be consistent with CheckRedirect, in this case the response's Body has already been drained and closed. The *http.Response.Body field will be nil in that case.
type Config ¶
type Config struct {
// Retries is the number of attempts to retry an HTTP transaction. This value
// does not include the initial attempt. The maximum number of HTTP transactions
// will be 1+Retries, accounting for the initial attempt.
//
// If this value is unset or nonpositive, no retries will be performed. Leaving this
// value unset will disable retries even if any other fields of this type are set.
Retries int `json:"retries" yaml:"retries"`
// MaxElapsedTime is the optional duration that all HTTP transactions together cannot
// exceed. This value includes the initial attempt with all retries. If this duration
// is exceeded, retry attempts will be short circuited.
//
// There is no default for this field. Leaving this field unset means that retries up to
// the Retries value will continue unless the request's context expires.
MaxElapsedTime time.Duration `json:"maxElapsedTime" yaml:"maxElapsedTime"`
// Interval is the base duration between each retry attempt. If nonpositive, DefaultInterval
// is used.
//
// In the simple case, when Multiplier and Jitter are unset, this is the interval
// between each retry.
//
// If Multiplier is set to a positive value, typically greater than 1.0, then each
// successive retry waits an amount equal to Interval*(Multiplier^n), where n is
// the current 0-based retry. Although a Multiplier of less than 1.0 is allowed, it's discouraged
// since that means each retry waits less time than the previous retry.
//
// If a Jitter is set, then each retry's interval is multiplied by a random number
// in the range [1-Jitter,1+Jitter]. This is over and above any Multiplier value.
Interval time.Duration `json:"interval" yaml:"interval"`
// Multiplier is the factor applied to each retry interval. If nonpositive, no multiplier
// is used. There is no default for this field.
//
// Each retry's interval is computed by (Previous*Multiplier), not including Jitter.
// A Multiplier value of less than 1.0 will result in decreasing wait times for each retry.
Multiplier float64 `json:"multiplier" yaml:"multiplier"`
// Jitter is the factor used to determine random intervals. The actual interval
// between retries is generated by multiplying by a random number in the range
// [1-Jitter, 1+Jitter]. That is, the Jitter is a percentage above and below the
// base interval.
//
// Note that the internal algorithm avoids floating point math in favor of fixed point.
// Only (3) decimal places to the right of the Jitter value are supported, e.g. 0.25
// is honored, but 0.623541 would be truncated to 0.624.
//
// If this field is not in the open range (0.0, 1.0), no jitter is used.
Jitter float64 `json:"jitter" yaml:"jitter"`
// Random is the optional source of randomness used in computing jitter.
// If this value is omitted, math/rand.New is used to compute a source
// of randomness with the current time as the seed.
Random Random `json:"-" yaml:"-"`
// Timer is the timer strategy used to creating channels for awaiting
// until the next retry interval. If unset, DefaultTimer is used.
Timer Timer `json:"-" yaml:"-"`
// Check is the predicate used to determine if the result of http.Client.Do
// can be retried. Even if this predicate returns true, the number of Retries
// will not be exceeded.
Check Check `json:"-" yaml:"-"`
}
Config is the set of configuration options for an HTTP client retry decorator
type GetBodyError ¶
type GetBodyError struct {
// Err is the error returned from GetBody
Err error
}
GetBodyError indicates that http.Request.GetBody returned an error. Retries cannot continue in this case, since the original request body is unavailable.
func (*GetBodyError) Error ¶
func (err *GetBodyError) Error() string
Error fulfills the error interface
type NoGetBodyError ¶
type NoGetBodyError struct {
// Initial is the error from the initial Do(request)
Initial error
}
NoGetBodyError indicates that the initial attempt at an HTTP transaction required a retry but that the *http.Request had no GetBody field.
If an initial attempt succeeded (i.e. did NOT require a retry), the GetBody field is ignored. This error only occurs if retries were required.
func (*NoGetBodyError) Error ¶
func (err *NoGetBodyError) Error() string
Error fulfills the error interface
type Random ¶
Random is the subset of rand.Rand methods used by this package to compute jitter. *rand.Rand implements this interface.
type State ¶
type State struct {
// contains filtered or unexported fields
}
State is the current state of a retry operation. Instances of this type are available in request context's during the initial attempt and any retries.
This type is never safe for concurrent access.
func GetState ¶
GetState returns the retry State associated with the given context. Decorated code can make use of this for metrics, logging, etc.
IMPORTANT: State is not safe for concurrent access. The State instance returned by this function should never be retained.
func (*State) Attempt ¶
Attempt is the 0-based attempt to execute this HTTP transaction. Zero (0) means the initial attempt. Positive values indicate the retry attempt. In other words, this method returns the number of attempts that have been tried previously.