backoff

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package backoff provides pluggable exponential backoff strategies, with optional jitter, for retry policies.

bi := backoff.NewFullJitterBackoffInterval(500 * time.Millisecond)
for {
    if err := doSomething(); err != nil {
        time.Sleep(bi.Next())
        continue
    }
    break
}

Jitter strategies are modeled after the AWS Architecture Blog reference "Exponential Backoff and Jitter": https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/

  • FullJitter implements that article's recommended (and, per its own simulation, most effective) strategy and is this package's default.
  • EqualJitter implements the article's "Equal Jitter" strategy, trading some desynchronization power for a wait that never gets too short.
  • DecorrelatedJitter implements the article's "Decorrelated Jitter" strategy as its own NextFunc rather than a JitterFunc, since its recurrence depends on the previously returned sleep instead of a Multiplier-based ramp -- see DecorrelatedNextFunc.
  • PercentJitter is this package's own narrower-band alternative and is not one of the strategies the article names.

Index

Constants

View Source
const DefaultMaxAttempts = 3

DefaultMaxAttempts is the default number of attempts at DefaultMaxInterval before resetting ExponentialBackoff to its initial interval (e.g., 3 attempts). It controls how long the backoff persists at the maximum delay.

View Source
const DefaultMaxInterval = 1 * time.Minute

DefaultMaxInterval is the default maximum delay for ExponentialBackoff (e.g., 1 minute). It caps the interval to prevent excessively long retries.

View Source
const DefaultMultiplier = 2.0

DefaultMultiplier is the default factor by which the interval grows in ExponentialBackoff (e.g., 2.0 means each attempt’s delay is 2.0 times the previous one). It determines the exponential growth rate. While 2.0 is a classic default in many sources, modern AWS SDKs and some HTTP clients often use 1.5 as a less aggressive default (to avoid excessive wait times early). See ModerateBackoffMultiplier for a gentler alternative.

View Source
const DefaultRandomizer = 0.25

DefaultRandomizer is the default jitter magnitude for ExponentialBackoff specifying the relative deviation (e.g., 0.25 means ±25% of the interval). It controls the randomness added to desynchronize retries.

View Source
const DefaultStartInterval = 250 * time.Millisecond

DefaultStartInterval is the default starting delay for ExponentialBackoff (e.g., 500ms for the first retry). It sets the baseline for the backoff sequence.

View Source
const ModerateMultiplier = 1.5

ModerateMultiplier is an alternative multiplier for ExponentialBackoff, increasing the interval by 1.5x each attempt for a gentler escalation compared to BackoffMultiplier. Use this for scenarios where slower retry growth is preferred, such as less contended systems.

Variables

This section is empty.

Functions

func DecorrelatedNextFunc

func DecorrelatedNextFunc(b *BackoffInterval) time.Duration

DecorrelatedNextFunc implements the "Decorrelated Jitter" strategy from the AWS "Exponential Backoff and Jitter" reference (https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/):

sleep = min(cap, random(base, sleep_prev * 3))

Unlike ExponentialNextFunc, there is no deterministic ramp separate from the jitter: each call's randomization is derived directly from the previously returned sleep, not from a Multiplier-based doubling. The AWS reference defines no MaxAttempts/Cycles reset for this strategy, so none is applied here -- the sequence runs indefinitely.

Thread-safe: locks the BackoffInterval's mutex to ensure consistent state updates.

func DecorrelatedResetFunc

func DecorrelatedResetFunc(b *BackoffInterval)

DecorrelatedResetFunc resets a Decorrelated Jitter sequence's sleep back to the initial interval. Thread-safe: locks the BackoffInterval's mutex to ensure consistent state updates.

func EqualJitter

func EqualJitter(interval time.Duration, _ *ExponentialConfig) time.Duration

EqualJitter implements the "Equal Jitter" strategy from the AWS "Exponential Backoff and Jitter" reference (https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/): sleep = half + random(0, half), where half = interval/2. It always keeps at least half of the computed interval, trading some of FullJitter's desynchronization power for a wait that never collapses close to zero -- useful when a very short retry would still likely fail (e.g. the remote side needs a minimum recovery time).

func ExponentialNextFunc

func ExponentialNextFunc(b *BackoffInterval) time.Duration

ExponentialNextFunc implements the exponential backoff logic for BackoffInterval. It returns the next interval duration for a retry attempt, updating the internal state accordingly. The interval increases exponentially with each call, up to the configured maximum. If the maximum interval is reached for a number of attempts specified by MaxAttempts, the cycle is reset and begins again from the initial interval. If jitter is enabled (Jittered == true), the interval is randomized within a range defined by the Randomizer setting to help prevent synchronized retries.

Thread-safe: locks the BackoffInterval's mutex to ensure consistent state updates.

func ExponentialResetFunc

func ExponentialResetFunc(b *BackoffInterval)

ExponentialResetFunc resets the state of an Exponential backoff sequence to the initial configuration. It sets the interval and counters back to their starting values, so the next call will begin anew. Thread-safe: locks the BackoffInterval's mutex to ensure consistent state updates.

func FullJitter

func FullJitter(interval time.Duration, _ *ExponentialConfig) time.Duration

FullJitter implements the "Full Jitter" strategy from the AWS "Exponential Backoff and Jitter" reference (https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/): sleep = random(0, interval). It desynchronizes retrying clients more effectively than PercentJitter, including on the very first (cold-start) attempt, and is the package's default jitter strategy.

func PercentJitter

func PercentJitter(interval time.Duration, config *ExponentialConfig) time.Duration

PercentJitter randomizes interval within a symmetric band of ±config.Randomizer (e.g. 0.25 means ±25%). If Randomizer <= 0, interval is returned unchanged. This is the package's original jitter formula; it does not match any of the strategies named in the AWS "Exponential Backoff and Jitter" reference (see FullJitter), but is kept as an explicit opt-in.

Types

type Backoff

type Backoff interface {
	Current() time.Duration

	// Next returns the duration to wait before the next retry attempt.
	// The duration may vary depending on the backoff strategy (e.g., fixed,
	// exponential).
	Next() time.Duration

	// Reset resets the backoff state to its initial configuration, allowing
	// the backoff sequence to start anew.
	Reset()

	// WrapError wraps err with the current backoff interval, so callers can
	// surface how long the next retry will wait without losing the original
	// error via errors.Is/errors.As.
	WrapError(err error) error
}

Backoff defines an interface for backoff strategies that generate retry delays. Implementations provide the next delay duration and a method to reset the backoff state.

type BackoffInterval

type BackoffInterval struct {
	// Interval is the current Interval duration, used as the default if no
	// nextFunc is set.
	Interval time.Duration

	// InitialInterval is the initial interval, used as the default if no
	// nextFunc is set.
	InitialInterval time.Duration

	// Config is an optional configuration object (e.g., *ExponentialConfig)
	// associated with the backoff logic.
	Config any

	// State is an optional state object (e.g., *ExponentialState) for
	// maintaining backoff progress.
	State any
	// contains filtered or unexported fields
}

BackoffInterval implements a flexible backoff mechanism with pluggable logic for generating the next interval and resetting state.

func NewBackoffInterval

func NewBackoffInterval(interval time.Duration) *BackoffInterval

NewBackoffInterval creates a new BackoffInterval with the specified initial interval. By default, the returned BackoffInterval has no nextFunc or resetFunc set, so it will always return the provided interval unless those are configured.

func NewDecorrelatedBackoffInterval

func NewDecorrelatedBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewDecorrelatedBackoffInterval constructs a new BackoffInterval using the Decorrelated Jitter strategy. The first argument is the initial interval, used as both the recurrence's base and the starting sleep (required). You may override config/state by passing string-keyed options, e.g.:

NewDecorrelatedBackoffInterval(
    10*time.Second,
    "config", &DecorrelatedConfig{...},
)

func NewEqualJitterBackoffInterval

func NewEqualJitterBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewEqualJitterBackoffInterval constructs an exponential backoff using the "Equal Jitter" strategy (see EqualJitter): each wait stays within [interval/2, interval] instead of ranging down to zero. Prefer this over FullJitter when a very short wait would still likely fail against the resource being retried.

func NewExponentialBackoffInterval

func NewExponentialBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewExponentialBackoffInterval constructs a new BackoffInterval using exponential settings. The first argument is the initial interval (required). You may override config/state by passing string-keyed options, e.g.:

NewExponentialBackoffInterval(
    10*time.Second,
    "config", &ExponentialConfig{...},
    "state", &ExponentialState{...},
)

func NewFullJitterBackoffInterval

func NewFullJitterBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewFullJitterBackoffInterval constructs an exponential backoff using the "Full Jitter" strategy (see FullJitter): each wait is randomized across the entire range [0, interval]. This spreads out retrying clients the most and is the strategy AWS's "Exponential Backoff and Jitter" reference found most effective at reducing total client/server work -- use it as the default choice for retrying against a shared/remote resource unless you have a specific reason to prefer a narrower spread.

func NewJitterBackoffInterval

func NewJitterBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewJitterBackoffInterval constructs an exponential backoff with jitter enabled using whichever JitterStrategy the caller configures (via the "config" option); if none is set, it defaults to FullJitter. Prefer the explicit NewFullJitterBackoffInterval / NewPercentJitterBackoffInterval constructors when you want a specific strategy without reaching into Config yourself.

func NewPercentJitterBackoffInterval

func NewPercentJitterBackoffInterval(interval time.Duration,
	options ...any) *BackoffInterval

NewPercentJitterBackoffInterval constructs an exponential backoff using the "Percent Jitter" strategy (see PercentJitter): each wait stays within ±Randomizer of the computed interval instead of ranging down to zero. It desynchronizes retries less aggressively than FullJitter, but keeps waits close to the "expected" backoff curve, which is useful when a caller (or a human reading logs) needs the wait time to stay roughly predictable.

func (*BackoffInterval) Current

func (b *BackoffInterval) Current() time.Duration

Current returns the current interval duration for this backoff instance. This method is thread-safe.

func (*BackoffInterval) Next

func (b *BackoffInterval) Next() time.Duration

Next returns the duration to wait before the next retry attempt by invoking the configured nextFunc. If no nextFunc is set, it returns the current interval as a fixed delay.

func (*BackoffInterval) Reset

func (b *BackoffInterval) Reset()

Reset resets the backoff state to its initial configuration, allowing the backoff sequence to start anew. If no resetFunc is configured, this is a no-op.

func (*BackoffInterval) WithConfig

func (b *BackoffInterval) WithConfig(config any) *BackoffInterval

WithConfig sets the configuration object for the BackoffInterval and returns the instance for chaining.

The config can be any type (e.g., *ExponentialConfig).

func (*BackoffInterval) WithNextFunc

func (b *BackoffInterval) WithNextFunc(nextFunc NextFunc) *BackoffInterval

WithNextFunc sets the function that computes the next interval for the BackoffInterval and returns the instance for chaining.

func (*BackoffInterval) WithResetFunc

func (b *BackoffInterval) WithResetFunc(resetFunc ResetFunc) *BackoffInterval

WithResetFunc sets the function that resets the BackoffInterval's state to its initial configuration and returns the instance for chaining.

func (*BackoffInterval) WithState

func (b *BackoffInterval) WithState(state any) *BackoffInterval

WithState sets the state object for the BackoffInterval and returns the instance for chaining.

The state can be any type (e.g., *ExponentialState).

func (*BackoffInterval) WrapError

func (b *BackoffInterval) WrapError(err error) error

WrapError wraps err with the current backoff interval using %w, so the original error remains inspectable via errors.Is/errors.As while the message carries how long the next retry will wait.

type DecorrelatedConfig

type DecorrelatedConfig struct {
	// MaxInterval caps the maximum delay between retries.
	MaxInterval time.Duration
}

DecorrelatedConfig holds configuration parameters for DecorrelatedNextFunc.

type DecorrelatedState

type DecorrelatedState struct {
	// contains filtered or unexported fields
}

DecorrelatedState tracks the runtime state of a Decorrelated Jitter sequence: the previous sleep value the recurrence is based on.

type ExponentialConfig

type ExponentialConfig struct {
	// Jitter determines whether to apply randomization to each interval.
	Jitter bool

	// JitterStrategy selects the randomization formula applied when Jitter is
	// true. If nil, FullJitter is used.
	JitterStrategy JitterFunc

	// MaxAttempts is the number of attempts to use the maximum interval before
	// resetting.
	MaxAttempts int

	// MaxInterval caps the maximum delay between retries.
	MaxInterval time.Duration

	// Multiplier is the factor by which the interval increases after each
	// retry.
	Multiplier float64

	// Randomizer specifies the magnitude of jitter as a fraction of the
	// interval (e.g., 0.25 means ±25%). Only consulted by PercentJitter.
	Randomizer float64
}

ExponentialConfig holds configuration parameters for an exponential backoff strategy.

type ExponentialState

type ExponentialState struct {
	// Cycles counts the number of times the backoff sequence has reached maxed
	// out attempts and reset.
	Cycles int
	// contains filtered or unexported fields
}

ExponentialState tracks the runtime state of an exponential backoff sequence.

type JitterFunc

type JitterFunc func(interval time.Duration, config *ExponentialConfig) time.Duration

JitterFunc computes a jittered duration from the exponentially-ramped, already-capped interval. Implementations may consult config (e.g. Randomizer for PercentJitter) but must not mutate it.

type NextFunc

type NextFunc func(*BackoffInterval) time.Duration

NextFunc defines a function that, given a BackoffInterval, computes and returns the next interval duration.

type ResetFunc

type ResetFunc func(*BackoffInterval)

ResetFunc defines a function that, given a BackoffInterval, resets its internal state to the initial configuration.

Jump to

Keyboard shortcuts

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