Files

46 lines
1.0 KiB
Go

package retry
import (
"context"
"fmt"
"log/slog"
"time"
)
type Retrier struct {
maxRetries int
backoff []time.Duration
}
func NewRetrier(maxRetries int, backoff []time.Duration) *Retrier {
return &Retrier{maxRetries: maxRetries, backoff: backoff}
}
// DefaultRetrier returns a retrier with 3 attempts, exponential backoff: 1s, 5s, 30s.
func DefaultRetrier() *Retrier {
return NewRetrier(3, []time.Duration{1 * time.Second, 5 * time.Second, 30 * time.Second})
}
func (r *Retrier) Do(ctx context.Context, fn func() error) error {
var lastErr error
for attempt := 0; attempt <= r.maxRetries; attempt++ {
if attempt > 0 {
delay := r.backoff[attempt-1]
slog.Info("retrying", "attempt", attempt, "delay", delay)
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
err := fn()
if err == nil {
return nil
}
lastErr = err
slog.Warn("attempt failed", "attempt", attempt, "error", err)
}
return fmt.Errorf("all %d attempts failed, last error: %w", r.maxRetries+1, lastErr)
}