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 ¶
- func ConstantBackoff(initInterval time.Duration, attempt int) time.Duration
- func Do(ctx context.Context, fn RetryableFunc, opts ...Option) error
- func ExponentialBackoff(initInterval time.Duration, attempt int) time.Duration
- func LinearBackoff(initInterval time.Duration, attempt int) time.Duration
- type Backoff
- type OnRetryFunc
- type Option
- func WithBackoff(backoff Backoff) Option
- func WithCollectErrors() Option
- func WithConstantBackoff() Option
- func WithExponentialBackoff() Option
- func WithInitInterval(initInterval time.Duration) Option
- func WithJitter(factor float64) Option
- func WithLinearBackoff() Option
- func WithMaxAttempts(maxAttempts int) Option
- func WithMaxElapsed(maxElapsed time.Duration) Option
- func WithMaxInterval(maxInterval time.Duration) Option
- func WithOnRetry(hook OnRetryFunc) Option
- func WithPanicHandler(handler PanicHandler) Option
- func WithRetryable(retryable func(error) bool) Option
- type PanicHandler
- type RetryableFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConstantBackoff ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
WithInitInterval sets the initial wait between attempts. Default is 500ms. Panics if initInterval <= 0.
func WithJitter ¶
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 ¶
WithMaxAttempts sets the maximum number of attempts. Default is 3.
func WithMaxElapsed ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.