Documentation
¶
Overview ¶
Package retry provides exponential backoff retry mechanisms for transient failures.
This package wraps github.com/cenkalti/backoff/v5 with application-specific retry patterns and error handling semantics. It offers several retry strategies:
- Execute: Retries an operation until it succeeds or times out
- ExecuteWithResult: Generic version that returns a result on success
- ExecuteSQL: Specialized retry for SQL operations
- WaitForCondition: Polls a condition until it becomes true
- Sustain: Keeps a long-running operation alive, restarting on transient failures
The package defines special error types to control retry behavior:
- ErrNonRetryable: Wraps permanent failures that should stop retries immediately
- ErrBackOff: Indicates transient errors that should trigger exponential backoff
Retry behavior is configured through the Profile struct, which defines:
- InitialInterval: Starting wait time between retries
- RandomizationFactor: Jitter to prevent thundering herd
- Multiplier: Factor by which wait time increases each retry
- MaxInterval: Maximum wait time between retries
- MaxElapsedTime: Total time budget for all retries (0 = unlimited)
Example Usage:
// Simple retry with default profile
err := retry.Execute(ctx, nil, func() error {
return someOperation()
})
// Retry with custom profile and result
profile := &retry.Profile{
InitialInterval: 100 * time.Millisecond,
MaxElapsedTime: 30 * time.Second,
}
result, err := retry.ExecuteWithResult(ctx, profile, func() (*Data, error) {
return fetchData()
})
// Keep a service running with automatic restart
err := retry.Sustain(ctx, profile, func() error {
return runService() // Returns ErrBackOff on transient errors
})
Index ¶
- Variables
- func Execute(ctx context.Context, p *Profile, o func() error) error
- func ExecuteSQL(ctx context.Context, p *Profile, e executor, sqlStmt string, args ...any) error
- func ExecuteWithResult[T any](ctx context.Context, p *Profile, operation func() (T, error)) (T, error)
- func Sustain(ctx context.Context, p *Profile, op func() error) error
- func WaitForCondition(ctx context.Context, p *Profile, condition func() bool) bool
- type Profile
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNonRetryable represents an error that should not trigger a retry. // It's used to wrap an underlying error condition when an operation // fails and retrying would be useless. // The code performing retries will check for this error type // (e.g., using errors.Is) and stop the retry loop if found. ErrNonRetryable = errors.New("cannot recover from error") // ErrBackOff is returned for transient errors specifically on an existing connection, // implying the initial connection was successful. Retry the operation after a backoff delay. ErrBackOff = errors.New("backoff required before retrying") )
Functions ¶
func Execute ¶
Execute executes the given operation repeatedly until it succeeds or a timeout occurs. It returns nil on success, or the error returned by the final attempt on timeout.
func ExecuteSQL ¶
ExecuteSQL executes the given SQL statement until it succeeds or a timeout occurs.
func ExecuteWithResult ¶
func ExecuteWithResult[T any](ctx context.Context, p *Profile, operation func() (T, error)) (T, error)
ExecuteWithResult executes the given operation repeatedly until it succeeds or a timeout occurs. It returns the result of the operation on success, or an error on timeout. This is a generic version that can return any type T.
func Sustain ¶
Sustain attempts to keep a continuous operation `op` running indefinitely. Unlike Execute which retries until success, Sustain is designed for long-running operations that should continue running until explicitly stopped or a permanent failure occurs.
Operation Behavior:
- If op returns nil: Operation is running smoothly, Sustain resets backoff and retries immediately
- If op returns ErrBackOff: Transient error, Sustain applies exponential backoff before retrying
- If op returns ErrNonRetryable: Permanent failure, Sustain stops and returns the error
- If op returns any other error: Retries immediately (treated as transient)
Sustain stops and returns when:
- op returns an error wrapping ErrNonRetryable (permanent failure),
- The context ctx is cancelled (returns context error),
- The backoff strategy times out after MaxElapsedTime of continuous ErrBackOff errors.
func WaitForCondition ¶
WaitForCondition repeatedly evaluates the given condition function until it returns true or a timeout occurs. It uses exponential backoff between attempts as defined by the retry profile. Returns nil when the condition is satisfied, or an error if the context is cancelled or max elapsed time is reached.
Types ¶
type Profile ¶
type Profile struct {
InitialInterval time.Duration `mapstructure:"initial-interval" yaml:"initial-interval"`
RandomizationFactor float64 `mapstructure:"randomization-factor" yaml:"randomization-factor"`
Multiplier float64 `mapstructure:"multiplier" yaml:"multiplier"`
MaxInterval time.Duration `mapstructure:"max-interval" yaml:"max-interval"`
MaxElapsedTime time.Duration `mapstructure:"max-elapsed-time" yaml:"max-elapsed-time"`
}
Profile can be used to define the backoff properties for retries.
After MaxElapsedTime, the backoff method returns the underlying error. It never stops if MaxElapsedTime == 0.
This is used as a workaround for known issues:
- Dropping a database with proximity to accessing it. See: https://support.yugabyte.com/hc/en-us/articles/10552861830541-Unable-to-Drop-Database.
- Creating/dropping tables immediately after creating a database. See: https://github.com/yugabyte/yugabyte-db/issues/14519.
func (*Profile) NewBackoff ¶
func (p *Profile) NewBackoff() *backoff.ExponentialBackOff
NewBackoff creates a new backoff.ExponentialBackOff instance with this profile.
Note: MaxElapsedTime is not set on the backoff instance itself. In backoff/v5, MaxElapsedTime is passed separately to backoff.Retry() as a configuration option via backoff.WithMaxElapsedTime(). This allows the same backoff instance to be reused with different timeout policies.
func (*Profile) WithDefaults ¶
WithDefaults returns a clone of this profile with default values.