Documentation
¶
Overview ¶
Package retry provides a linear-backoff retry loop.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Do ¶
Do calls fn up to attempts times (attempts < 1 is treated as 1), stopping at the first success. Between attempts it sleeps attempt*backoffUnit, growing the pause linearly with each retry. ctx cancellation aborts immediately. An error fn wrapped with Stop ends the loop at once (see Stop). The last error is returned if every attempt fails.
func Stop ¶
Stop wraps err so Do returns it immediately instead of spending the remaining attempts on it. It is nil-safe: Stop(nil) is nil.
The caller decides what is unretryable, because only it knows why the attempt failed. The case this exists for is a per-attempt timeout expiring: attempts: retries a transient fault, but it cannot buy more time, so a second attempt against the same budget just re-fails deterministically and bills twice for it.
Do unwraps the marker before returning, so it never escapes this package: callers' errors.As/errors.Is checks and the final error message see the original chain unchanged.
func StopOnDeadline ¶
StopOnDeadline marks err unretryable when attemptCtx's own deadline is what expired: attemptCtx is done while the enclosing ctx is still live. It is the one place the "a timeout is not transient" rule lives, shared by all three retry scaffolds (retryWithTimeout in internal/pipeline, runPrepared and RunFix in internal/agent), each of which owns the attempt context it passes.
Testing the context rather than errors.Is(err, context.DeadlineExceeded) is deliberate: a deadline from *inside* an attempt — an MCP or HTTP client's own timeout — is an ordinary transient fault and must stay retryable. Only the step's own timeout: ends the loop.
A nil err, a live attemptCtx, or a canceled ctx (a job abort, which Do handles on its own path) all pass err through untouched.
Types ¶
This section is empty.