Retry with exponential backoff and jitter
Go
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
// Retry calls fn with exponential backoff and jitter until it succeeds or ctx ends.
func Retry(ctx context.Context, attempts int, base time.Duration, fn func(context.Context) error) error {
var lastErr error
for attempt := 0; attempt < attempts; attempt++ {
if attempt > 0 {
delay := base * time.Duration(1<<uint(attempt-1))
jitter := time.Duration(rand.Int63n(int64(delay/2) + 1))
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay + jitter):
}
}
if lastErr = fn(ctx); lastErr == nil {
return nil
}
}
return fmt.Errorf("gave up after %d attempts: %w", attempts, lastErr)
}
func main() {
calls := 0
err := Retry(context.Background(), 3, 100*time.Millisecond, func(context.Context) error {
calls++
if calls < 3 {
return fmt.Errorf("temporary failure")
}
return nil
})
fmt.Println("err:", err, "calls:", calls)
}