Documentation
¶
Overview ¶
Package retry provides a simple and flexible retry mechanism for Go. It allows executing functions with automatic retry on failure, with configurable backoff strategies, retry conditions, and error handling.
The package is safe for concurrent use.
The package is inspired by Try::Tiny::Retry from Perl.
Basic usage:
url := "http://example.com" var body []byte err := retry.Do( func() error { resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() body, err = io.ReadAll(resp.Body) if err != nil { return err } return nil }, )
With data return:
body, err := retry.DoWithData( func() ([]byte, error) { resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) }, )
Index ¶
- func BackOffDelay(attempt uint, _ error, config *Config) time.Duration
- func Do(retryableFunc RetryableFunc, opts ...Option) error
- func DoWithData[T any](retryableFunc RetryableFuncWithData[T], opts ...Option) (T, error)
- func FixedDelay(_ uint, _ error, config *Config) time.Duration
- func FullJitterBackoffDelay(attempt uint, err error, config *Config) time.Duration
- func IsRecoverable(err error) bool
- func RandomDelay(_ uint, _ error, config *Config) time.Duration
- func Unrecoverable(err error) error
- type Config
- type DelayTypeFunc
- type Error
- type OnRetryFunc
- type Option
- func Attempts(attempts uint) Option
- func AttemptsForError(attempts uint, err error) Option
- func Context(ctx context.Context) Option
- func Delay(delay time.Duration) Option
- func DelayType(delayType DelayTypeFunc) Option
- func LastErrorOnly(lastErrorOnly bool) Option
- func MaxDelay(maxDelay time.Duration) Option
- func MaxJitter(maxJitter time.Duration) Option
- func OnRetry(onRetry OnRetryFunc) Option
- func RetryIf(retryIf RetryIfFunc) Option
- func UntilSucceeded() Option
- func WithTimer(t Timer) Option
- func WrapContextErrorWithLastError(wrap bool) Option
- type RetryIfFunc
- type RetryableFunc
- type RetryableFuncWithData
- type Timer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BackOffDelay ¶
BackOffDelay implements exponential backoff delay strategy. Each retry attempt doubles the delay, up to a maximum.
func Do ¶
func Do(retryableFunc RetryableFunc, opts ...Option) error
Do executes the retryable function with the provided options. It returns nil if the function succeeds, or an error if all retry attempts fail.
By default, it will retry up to 10 times with exponential backoff and jitter. The behavior can be customized using Option functions.
func DoWithData ¶
func DoWithData[T any](retryableFunc RetryableFuncWithData[T], opts ...Option) (T, error)
DoWithData executes the retryable function with the provided options and returns the function's data. It returns the data and nil error if the function succeeds, or zero value and error if all retry attempts fail.
By default, it will retry up to 10 times with exponential backoff and jitter. The behavior can be customized using Option functions.
func FixedDelay ¶
FixedDelay implements a constant delay strategy. The delay is always config.delay regardless of attempt number.
func FullJitterBackoffDelay ¶
FullJitterBackoffDelay implements exponential backoff with full jitter. It returns a random delay between 0 and min(maxDelay, baseDelay * 2^attempt).
func IsRecoverable ¶
IsRecoverable reports whether err is recoverable. It returns false if err is or wraps an unrecoverable error.
func RandomDelay ¶
RandomDelay implements a random delay strategy. Returns a random duration between 0 and config.maxJitter.
func Unrecoverable ¶
Unrecoverable wraps an error to mark it as unrecoverable. When an unrecoverable error is returned, the retry mechanism will stop immediately.
Types ¶
type Config ¶
type Config struct {
// contains filtered or unexported fields
}
Config holds all configuration options for retry behavior. It is typically populated using Option functions and should not be constructed directly. Use the various Option functions like Attempts, Delay, and RetryIf to configure retry behavior.
type DelayTypeFunc ¶
DelayTypeFunc calculates the delay duration before the next retry attempt. The attempt parameter is the zero-based index of the attempt.
func CombineDelay ¶
func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc
CombineDelay creates a DelayTypeFunc that sums the delays from multiple strategies. The total delay is capped at math.MaxInt64 to prevent overflow.
type Error ¶
type Error []error
Error represents a collection of errors that occurred during retry attempts. It implements the error interface and provides compatibility with errors.Is, errors.As, and errors.Unwrap.
func (Error) As ¶
As finds the first error in e that matches target, and if so, sets target to that error value and returns true. It implements support for errors.As.
func (Error) Error ¶
Error returns a string representation of all errors that occurred during retry attempts. Each error is prefixed with its attempt number.
func (Error) Is ¶
Is reports whether any error in e matches target. It implements support for errors.Is.
func (Error) Unwrap ¶
Unwrap returns the last error for compatibility with errors.Unwrap. When you need to unwrap all errors, you should use WrappedErrors instead.
Example:
err := Do( func() error { return errors.New("original error") }, Attempts(1), ) fmt.Println(errors.Unwrap(err)) // "original error" is printed
func (Error) WrappedErrors ¶
WrappedErrors returns the list of errors that this Error is wrapping. It is an implementation of the `errwrap.Wrapper` interface in package [errwrap](https://github.com/hashicorp/errwrap) so that `retry.Error` can be used with that library.
type OnRetryFunc ¶
OnRetryFunc is the signature for functions called after each retry attempt. The attempt parameter is the zero-based index of the attempt.
type Option ¶
type Option func(*Config)
Option configures retry behavior. Options are applied in the order provided to Do or DoWithData. Later options override earlier ones if they modify the same configuration field.
func Attempts ¶
Attempts sets the maximum number of retry attempts. Setting to 0 enables infinite retries. Default is 10.
func AttemptsForError ¶
AttemptsForError sets a specific number of retry attempts for a particular error. These attempts are counted against the total retry limit. The retry stops when either the specific error limit or total limit is reached. Note: errors are compared using errors.Is for matching.
func Context ¶
Context sets the context for retry operations. The retry loop will stop if the context is cancelled or times out. Default is context.Background().
Example with timeout:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() retry.Do( func() error { return doSomething() }, retry.Context(ctx), )
func Delay ¶
Delay sets the base delay duration between retry attempts. Default is 100ms. The actual delay may be modified by the DelayType function.
func DelayType ¶
func DelayType(delayType DelayTypeFunc) Option
DelayType sets the delay calculation function between retries. Default is CombineDelay(BackOffDelay, RandomDelay).
func LastErrorOnly ¶
LastErrorOnly configures whether to return only the last error that occurred, or wrap all errors together. Default is false (return all errors).
func MaxDelay ¶
MaxDelay sets the maximum delay duration between retry attempts. This caps the delay calculated by DelayType functions. By default, there is no maximum (0 means no limit).
func MaxJitter ¶
MaxJitter sets the maximum random jitter duration for RandomDelay. Default is 100ms.
func OnRetry ¶
func OnRetry(onRetry OnRetryFunc) Option
OnRetry sets a callback function that is called after each failed attempt. This is useful for logging or other side effects.
Example:
retry.Do( func() error { return errors.New("some error") }, retry.OnRetry(func(attempt uint, err error) { log.Printf("#%d: %s\n", attempt, err) }), )
func RetryIf ¶
func RetryIf(retryIf RetryIfFunc) Option
RetryIf controls whether a retry should be attempted after an error (assuming there are any retry attempts remaining)
skip retry if special error example:
retry.Do( func() error { return errors.New("special error") }, retry.RetryIf(func(err error) bool { if err.Error() == "special error" { return false } return true }) )
By default RetryIf stops execution if the error is wrapped using `retry.Unrecoverable`, so above example may also be shortened to:
retry.Do( func() error { return retry.Unrecoverable(errors.New("special error")) } )
func UntilSucceeded ¶
func UntilSucceeded() Option
UntilSucceeded configures infinite retry attempts until success. Equivalent to Attempts(0).
func WithTimer ¶
WithTimer provides a way to swap out timer implementations. This is primarily useful for testing.
Example:
type mockTimer struct{} func (mockTimer) After(d time.Duration) <-chan time.Time { return time.After(0) // immediate return for tests } retry.Do( func() error { ... }, retry.WithTimer(mockTimer{}), )
func WrapContextErrorWithLastError ¶
WrapContextErrorWithLastError configures whether to wrap context errors with the last function error. This is useful when using infinite retries (Attempts(0)) with context cancellation, as it preserves information about what error was occurring when the context expired. Default is false.
ctx, cancel := context.WithCancel(context.Background()) defer cancel() retry.Do( func() error { ... }, retry.Context(ctx), retry.Attempts(0), retry.WrapContextErrorWithLastError(true), )
type RetryIfFunc ¶
RetryIfFunc is the signature for functions that determine whether to retry after an error. It returns true if the error is retryable, false otherwise.
type RetryableFunc ¶
type RetryableFunc func() error
RetryableFunc is the function signature for retryable functions used with Do.
type RetryableFuncWithData ¶
RetryableFuncWithData is the function signature for retryable functions that return data. Used with DoWithData.
type Timer ¶
type Timer interface { // After returns a channel that sends the current time after the duration elapses. // It should behave like time.After. After(time.Duration) <-chan time.Time }
Timer provides an interface for time operations in retry logic. This abstraction allows for mocking time in tests and implementing custom timing behaviors. The standard implementation uses time.After.
Security note: Custom Timer implementations must return a valid channel that either receives a time value or blocks. Returning nil will cause the retry to fail immediately.