Backoff
Package backoff implements backoff logic for retry loops using Go 1.23+ iterators.
Usage
Retries with Attempts()
Use Attempts() for bounded retries. The iterator sleeps the backoff duration after each iteration before yielding the next attempt:
for attempt := range backoff.Attempts(ctx, time.Second, 30*time.Second, backoff.Exponential(2), 5) { if err := doSomething(); err == nil { return nil } log.Printf("attempt %d failed", attempt) // Sleep happens automatically before next iteration } return errors.New("max retries exceeded")
With Timeout
Use context.WithTimeout to limit total elapsed time:
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() for attempt := range backoff.Attempts(ctx, time.Second, 30*time.Second, backoff.Exponential(2), 10) { if err := doSomething(); err == nil { return nil } } return ctx.Err() // context.DeadlineExceeded after 2 minutes
With Jitter
Jitter is useful in distributed systems to avoid thundering herd problems:
for attempt := range backoff.Attempts(ctx, time.Second, 30*time.Second, backoff.Jitter(backoff.Exponential(2), 0.5), 5) { if err := doSomething(); err == nil { return nil } }
Manual Sleep with Delays()
Use Delays() when you need control over the sleep. Unlike Attempts(), this iterator does not sleep—it yields the delay value for you to handle:
for attempt, delay := range backoff.Delays(ctx, time.Second, 30*time.Second, backoff.Exponential(2)) { if err := doSomething(); err == nil { return nil } log.Printf("attempt %d failed, retrying in %v", attempt, delay) time.Sleep(delay) } // Yields: (1, 1s), (2, 2s), (3, 4s), (4, 8s), (5, 16s), (6, 30s), ...
Step Functions
| Function | Description |
|---|---|
Fixed() |
Always returns base (equivalent to Linear(0)) |
Linear(d) |
Adds d each iteration: base, base+d, base+2d, ... |
Incremental(m) |
Multiplies base by count: base, base*m, base*2m, ... |
Exponential(f) |
Exponential growth: base, base*f, base*f^2, ... |
Jitter(fn, factor) |
Wraps any step function with randomized jitter in [d-factor*d, d] |
Contributions
Contributions are welcome via Pull Requests.