import Foundation enum ProviderCandidateRetryRunnerError: Error { case noCandidates } enum ProviderCandidateRetryRunner { static func run( _ candidates: [Candidate], shouldRetry: (Error) -> Bool, onRetry: (Candidate, Error) -> Void = { _, _ in }, attempt: (Candidate) async throws -> Output) async throws -> Output { guard !candidates.isEmpty else { throw ProviderCandidateRetryRunnerError.noCandidates } for (index, candidate) in candidates.enumerated() { do { return try await attempt(candidate) } catch { let hasMoreCandidates = index + 1 < candidates.count guard hasMoreCandidates, shouldRetry(error) else { throw error } onRetry(candidate, error) } } throw ProviderCandidateRetryRunnerError.noCandidates } }