retryWithInterval calls fn up to maxAttempts times, waiting interval between attempts. Stops on success, non-retryable error, or context cancellation.
(ctx context.Context, logger slog.Logger, interval time.Duration, maxAttempts int, fn func() error)
| 91 | // interval between attempts. Stops on success, non-retryable |
| 92 | // error, or context cancellation. |
| 93 | func retryWithInterval(ctx context.Context, logger slog.Logger, interval time.Duration, maxAttempts int, fn func() error) error { |
| 94 | var lastErr error |
| 95 | attempt := 0 |
| 96 | for r := retry.New(interval, interval); r.Wait(ctx); { |
| 97 | lastErr = fn() |
| 98 | if lastErr == nil || !isRetryableError(lastErr) { |
| 99 | return lastErr |
| 100 | } |
| 101 | attempt++ |
| 102 | if attempt >= maxAttempts { |
| 103 | break |
| 104 | } |
| 105 | logger.Warn(ctx, "transient error, retrying", |
| 106 | slog.Error(lastErr), |
| 107 | slog.F("attempt", attempt), |
| 108 | ) |
| 109 | } |
| 110 | if lastErr != nil { |
| 111 | return lastErr |
| 112 | } |
| 113 | return ctx.Err() |
| 114 | } |
| 115 | |
| 116 | func (r *RootCmd) ssh() *serpent.Command { |
| 117 | var ( |