import Foundation struct RetryPolicy { let maxAttempts: Int let baseDelay: TimeInterval let maxDelay: TimeInterval let shouldRetry: (Error) -> Bool static let fileSave = RetryPolicy(maxAttempts: 4, baseDelay: 0.25, maxDelay: 4.0) { _ in true } static let network = RetryPolicy(maxAttempts: 3, baseDelay: 0.5, maxDelay: 8.0) { error in let retryable: Set = [NSURLErrorTimedOut, NSURLErrorNetworkConnectionLost, NSURLErrorNotConnectedToInternet, NSURLErrorCannotConnectToHost] return retryable.contains((error as NSError).code) } } func withRetry(policy: RetryPolicy, operation: @escaping () async throws -> T) async throws -> T { var lastError: Error? var delay = policy.baseDelay for attempt in 1...policy.maxAttempts { do { return try await operation() } catch { lastError = error guard policy.shouldRetry(error), attempt < policy.maxAttempts else { break } let jitter = Double.random(in: 0...0.3) * delay try? await Task.sleep(for: .seconds(min(delay + jitter, policy.maxDelay))) delay = min(delay * 2, policy.maxDelay) } } throw lastError ?? URLError(.unknown) }