Skip to content

Instantly share code, notes, and snippets.

@BrentMifsud
Created August 26, 2024 19:14
Show Gist options
  • Save BrentMifsud/8c13c60342633682159f53f53218015e to your computer and use it in GitHub Desktop.
Save BrentMifsud/8c13c60342633682159f53f53218015e to your computer and use it in GitHub Desktop.
Retrying Task
import Foundation
private extension Task where Failure == any Error {
static var backoffMultiplier: Int {
2
}
static func incrementRetryValues(currentRetry: inout Int, currentDelay: inout Int) {
currentRetry += 1
currentDelay = currentRetry == 0 ? 100 : currentDelay * Self.backoffMultiplier
}
}
extension Task where Failure == any Error {
/// Creates a task that retries itself the specified number of times
/// - Parameters:
/// - priority: task priority
/// - maxRetryCount: the number of retries before failure
/// - operation: the task operation
/// - shouldRetry: handler to retry on certain errors, defaults to false
/// - Returns: Operation result
static func retrying(
priority: TaskPriority? = nil,
maxRetryCount: Int = 5,
delayClock: any Clock<Duration> = ContinuousClock(),
operation: @escaping @Sendable () async throws -> Success,
retryWhile shouldRetry: @escaping (Error) -> Bool = { _ in false }
) -> Task<Success, Failure> {
Task(priority: priority) {
var currentRetry = 0
var currentDelay = 0
var finalError: any Error = _Concurrency.CancellationError()
repeat {
do {
try await delayClock.sleep(for: .milliseconds(currentDelay))
let success = try await operation()
return success
} catch let networkError as NetworkError {
incrementRetryValues(currentRetry: &currentRetry, currentDelay: &currentDelay)
if currentRetry == maxRetryCount {
finalError = networkError
}
continue
} catch let cancellationError as CancellationError {
throw cancellationError
} catch {
if shouldRetry(error) {
incrementRetryValues(currentRetry: &currentRetry, currentDelay: &currentDelay)
if currentRetry == maxRetryCount {
finalError = error
}
continue
} else {
throw error
}
}
} while currentRetry < maxRetryCount
throw finalError
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment