retry

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func Execute(ctx context.Context, p *Profile, o func() error) error

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

func ExecuteSQL(ctx context.Context, p *Profile, e executor, sqlStmt string, args ...any) error

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

func Sustain(ctx context.Context, p *Profile, op func() error) error

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

func WaitForCondition(ctx context.Context, p *Profile, condition func() bool) bool

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:

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

func (p *Profile) WithDefaults() *Profile

WithDefaults returns a clone of this profile with default values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL