retry

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package retry runs a fallible operation under a configurable retry policy: max attempts, initial interval, max interval cap, backoff strategy, jitter, panic handler, retryable-error predicate, max elapsed time, on-retry hook, and optional error aggregation.

Do reruns the operation while it returns a non-nil error, stopping when any of the following holds:

  • the operation succeeds (returns nil)
  • the configured maximum attempts has been reached
  • the configured retryable predicate says the error is not retryable
  • the configured maximum elapsed time has been reached
  • the context is canceled (the sleep between attempts is also canceled when ctx is done)

If fn returns nil, Do returns nil regardless of the ctx state - success is reported even when ctx was canceled during fn. Callers that need ctx cancellation to take precedence over a successful fn should check ctx.Err() after Do returns.

By default a panic in the RetryableFunc propagates to the caller. Pass WithPanicHandler to convert it into a returned error and stop retrying. Functions installed via WithBackoff and WithRetryable are NOT shielded by the package - they are expected to be pure and must not panic; a panic in them propagates to the caller of Do. The hook installed via WithOnRetry IS shielded: a panic inside it is logged via slog.Default and swallowed so retry can continue.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConstantBackoff

func ConstantBackoff(initInterval time.Duration, attempt int) time.Duration

ConstantBackoff returns initInterval regardless of attempt. It matches the default sleep behavior when no Backoff is configured but lets callers opt in explicitly via WithConstantBackoff.

func Do

func Do(ctx context.Context, fn RetryableFunc, opts ...Option) error

Do runs fn under the retry policy assembled from opts. See package doc for the stop conditions. Do panics if fn is nil.

func ExponentialBackoff

func ExponentialBackoff(initInterval time.Duration, attempt int) time.Duration

ExponentialBackoff returns initInterval * 2^(attempt-1), clamped at [maxBackoff] (24h) to avoid int64 overflow. attempt <= 1 returns initInterval as-is. initInterval <= 0 returns maxBackoff.

func LinearBackoff

func LinearBackoff(initInterval time.Duration, attempt int) time.Duration

LinearBackoff returns initInterval * attempt, clamped at [maxBackoff] (24h) to avoid int64 overflow. attempt <= 1 returns initInterval as-is. initInterval <= 0 returns maxBackoff (consistent with ExponentialBackoff).

Types

type Backoff

type Backoff func(initInterval time.Duration, attempt int) time.Duration

Backoff returns the wait time before the next attempt. attempt is the number of failed attempts so far (1 after the first failure, 2 after the second, and so on). initInterval is the value configured via WithInitInterval. A non-positive return value falls back to initInterval.

type OnRetryFunc

type OnRetryFunc func(ctx context.Context, attempt int, err error)

OnRetryFunc is invoked just before sleeping between attempts. The attempt argument is 1 after the first failure, 2 after the second, and so on; that is, "attempt N has just failed and a sleep for the (N+1)-th attempt is about to start". The hook is not invoked after the final failure (no further sleep follows). A panic raised inside the hook is recovered, logged via slog.Default, and swallowed so retry can continue.

The hook is called synchronously and counts toward the wall-clock time observed by the retry loop. Keep it fast; offload slow work (network I/O, blocking metric emission) to a goroutine if needed.

The hook may have already run for an attempt that does not actually execute, when ctx is canceled during the sleep that follows the hook. Treat the hook as "attempt N failed, sleep about to begin" rather than "attempt N+1 will run".

type Option

type Option func(o *options)

Option modifies the retry policy used by Do. Invalid values panic at Option construction time rather than being silently ignored, so misuse is caught loudly during development.

func WithBackoff

func WithBackoff(backoff Backoff) Option

WithBackoff installs a custom backoff strategy. A nil backoff means every retry waits exactly initInterval (before maxInterval cap and jitter).

func WithCollectErrors

func WithCollectErrors() Option

WithCollectErrors makes Do return all attempt errors joined via errors.Join instead of only the most recent one. Useful when every failure carries distinct context worth surfacing to the caller. Off by default.

func WithConstantBackoff

func WithConstantBackoff() Option

WithConstantBackoff installs ConstantBackoff as the backoff strategy. The behavior is identical to installing no Backoff (every retry waits exactly initInterval), but the explicit form documents intent at the call site and pairs symmetrically with WithLinearBackoff and WithExponentialBackoff.

func WithExponentialBackoff

func WithExponentialBackoff() Option

WithExponentialBackoff installs ExponentialBackoff as the backoff strategy. Equivalent to WithBackoff(ExponentialBackoff).

func WithInitInterval

func WithInitInterval(initInterval time.Duration) Option

WithInitInterval sets the initial wait between attempts. Default is 500ms. Panics if initInterval <= 0.

func WithJitter

func WithJitter(factor float64) Option

WithJitter randomizes the per-attempt sleep by +/- factor of the computed interval. For example WithJitter(0.5) on a 1s interval produces a uniform random sleep in [500ms, 1500ms]. Used to avoid thundering-herd effects when many clients retry at once. factor must be in [0, 1]; 0 disables jitter. Panics if factor is outside [0, 1].

func WithLinearBackoff

func WithLinearBackoff() Option

WithLinearBackoff installs LinearBackoff as the backoff strategy. Equivalent to WithBackoff(LinearBackoff).

func WithMaxAttempts

func WithMaxAttempts(maxAttempts int) Option

WithMaxAttempts sets the maximum number of attempts. Default is 3.

func WithMaxElapsed

func WithMaxElapsed(maxElapsed time.Duration) Option

WithMaxElapsed bounds the total wall-clock time spent retrying. Once exceeded, Do returns the most recent error. A value of 0 disables the bound. Panics if maxElapsed < 0.

func WithMaxInterval

func WithMaxInterval(maxInterval time.Duration) Option

WithMaxInterval caps the per-attempt sleep at maxInterval. The cap is applied after Backoff but before jitter, so jitter still scatters callers around the cap. A value of 0 disables the cap (an internal 24h hard cap still applies inside ExponentialBackoff to prevent overflow). Panics if maxInterval < 0.

func WithOnRetry

func WithOnRetry(hook OnRetryFunc) Option

WithOnRetry installs a hook invoked on every failure that will be followed by another attempt. Useful for logging or metrics. The hook is not called after the final failure. A panic raised inside the hook is recovered, logged via slog.Default with a stack trace, and swallowed so retry can continue. See OnRetryFunc for the full contract.

func WithPanicHandler

func WithPanicHandler(handler PanicHandler) Option

WithPanicHandler installs a panic handler. Without it, a panic in the retried function propagates to the caller of Do.

func WithRetryable

func WithRetryable(retryable func(error) bool) Option

WithRetryable installs a predicate that decides whether a non-nil error should be retried. Returning false stops the retry loop and surfaces the error to the caller. A nil predicate disables the check, so every error is retried until another stop condition fires.

type PanicHandler

type PanicHandler func(ctx context.Context, recovered any) error

PanicHandler converts a recovered panic value into an error. The returned error is treated like any other error returned by the operation: it is reported as the Do result and ends retrying. If no PanicHandler is configured, a panic propagates to the caller.

The handler is expected to be pure and must not panic; a panic inside the handler propagates to the caller of Do.

type RetryableFunc

type RetryableFunc func(ctx context.Context) error

RetryableFunc is the operation re-run by Do. The ctx is the same ctx passed to Do. Returning nil ends the retry loop with success; returning a non-nil error triggers retry handling, subject to the configured retryable predicate, max attempts, and max elapsed time.

Jump to

Keyboard shortcuts

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