retryWithFailFast invokes attempt up to policy.maxAttempts times. After each failure shouldRetry decides whether the loop continues; false returns immediately so the operator does not wait through pointless retries for deterministic failures OR for partial-success scenarios where retrying would disc
(ctx context.Context, attempt func() error, shouldRetry func(error) bool, policy retryPolicy)
| 377 | // Returns the LAST error observed (not a multierror) so the downstream |
| 378 | // wrap+hint sees the most recent failure for classification purposes. |
| 379 | func retryWithFailFast(ctx context.Context, attempt func() error, shouldRetry func(error) bool, policy retryPolicy) error { |
| 380 | var lastErr error |
| 381 | |
| 382 | for i := range policy.maxAttempts { |
| 383 | lastErr = attempt() |
| 384 | if lastErr == nil { |
| 385 | return nil |
| 386 | } |
| 387 | |
| 388 | if !shouldRetry(lastErr) { |
| 389 | return lastErr |
| 390 | } |
| 391 | |
| 392 | if i == policy.maxAttempts-1 { |
| 393 | break |
| 394 | } |
| 395 | |
| 396 | select { |
| 397 | case <-ctx.Done(): |
| 398 | //nolint:wrapcheck // context error is the operator-meaningful one when cancellation interrupts retry; preserving it lets the chart-template trace point at "context cancelled" rather than the last transport error. |
| 399 | return ctx.Err() |
| 400 | case <-time.After(policy.backoff(i)): |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | return lastErr |
| 405 | } |
| 406 | |
| 407 | // defaultShouldRetry is the pure class-based retry predicate: an |
| 408 | // error is retried iff its class is retryable. Convenient for |
no outgoing calls