Browse Questions
Answer: Wrap the request in a loop with a limited retry count. Optionally add exponential backoff — increasing delay between retries to avoid hammering the server.
Code Example:
func fetchWithRetry<T: Decodable>(
_ type: T.Type,
from url: URL,
maxRetries: Int = 3
) async throws -> T {
var lastError: Error?
for attempt in 0..<maxRetries {
do {
return try await fetch(type, from: url)
} catch {
lastError = error
// Don't retry on client errors (4xx)
if let apiError = error as? APIError,
case .unauthorized = apiError { throw error }
// Exponential backoff: 1s, 2s, 4s...
let delay = UInt64(pow(2.0, Double(attempt))) * 1_000_000_000
try await Task.sleep(nanoseconds: delay)
}
}
throw lastError ?? APIError.unknown
}