func Retry[T any]()

in gollm/factory.go [165:236]


func Retry[T any](
	ctx context.Context,
	config RetryConfig,
	isRetryable IsRetryableFunc,
	operation func(ctx context.Context) (T, error),
) (T, error) {
	var lastErr error
	var zero T // Zero value of the return type T

	log := klog.FromContext(ctx)

	backoff := config.InitialBackoff

	for attempt := 1; attempt <= config.MaxAttempts; attempt++ {
		// log.Printf("Executing operation, attempt %d of %d", attempt, config.MaxAttempts) // Optional verbose log
		result, err := operation(ctx)

		if err == nil {
			// Success
			return result, nil
		}
		lastErr = err // Store the last error encountered

		// Check if context was cancelled *after* the operation
		select {
		case <-ctx.Done():
			log.Info("Context cancelled after attempt %d failed.", "attempt", attempt)
			return zero, ctx.Err() // Return context error preferentially
		default:
			// Context not cancelled, proceed with error checking
		}

		if !isRetryable(lastErr) {
			log.Info("Attempt failed with non-retryable error", "attempt", attempt, "error", lastErr)
			return zero, lastErr // Return the non-retryable error immediately
		}

		log.Info("Attempt failed with retryable error", "attempt", attempt, "error", lastErr)

		if attempt == config.MaxAttempts {
			// Max attempts reached
			break
		}

		// Calculate wait time
		waitTime := backoff
		if config.Jitter {
			waitTime += time.Duration(rand.Float64() * float64(backoff) / 2)
		}

		log.Info("Waiting before next attempt", "waitTime", waitTime, "attempt", attempt+1, "maxAttempts", config.MaxAttempts)

		// Wait or react to context cancellation
		select {
		case <-time.After(waitTime):
			// Wait finished
		case <-ctx.Done():
			log.Info("Context cancelled while waiting for retry after attempt %d.", "attempt", attempt)
			return zero, ctx.Err()
		}

		// Increase backoff
		backoff = time.Duration(float64(backoff) * config.BackoffFactor)
		if backoff > config.MaxBackoff {
			backoff = config.MaxBackoff
		}
	}

	// If the loop finished, it means all attempts failed
	errFinal := fmt.Errorf("operation failed after %d attempts: %w", config.MaxAttempts, lastErr)
	return zero, errFinal
}