Created
August 11, 2022 21:18
-
-
Save BigZaphod/50ccb254a6e7047ff5693a4381a3be37 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Sean Heber on 8/11/22. | |
// | |
import Foundation | |
enum ExponentialBackoffError : Error { | |
case retryLimitExceeded | |
} | |
/// Runs the `operation` until it succeeds. | |
/// Success here is defined as not throwing, so if `operation` throws any errors, this function swallows them, waits a bit, and runs the `operation` again until either we reach the maximum attempts allowed or the task is cancelled. | |
func retryWithExponentialBackoff<Result>(base: Double = 0.25, maxInterval: Double = 60, maxAttempts: Int? = nil, operation: () async throws -> Result) async throws -> Result { | |
var attempt = 0 | |
while maxAttempts == nil || attempt < maxAttempts! { | |
try Task.checkCancellation() | |
do { | |
return try await operation() | |
} catch { | |
// errors from the operation are ignored! | |
} | |
// This uses an exponential backoff with jitter (hence the randomness). | |
let sleep = base * Double(pow(Double(2), Double(attempt))) | |
let seconds = Double.random(in: 0...min(maxInterval, sleep)) | |
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) | |
attempt += 1 | |
} | |
throw ExponentialBackoffError.retryLimitExceeded | |
} |
And of course the onFailure
function could also be made async
there, too, and who knows what crazy possibilities that might unlock.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's a variation on this idea that uses a function to decide if the thrown error is something we care about or not. If
onFailure
throws, then that'll cancel the retrying - otherwise it keeps going. This way you can implement your own maxAttempts logic, log the errors, or decide if certain errors are actually failures while ignoring and retrying for others.