Skip to content

Instantly share code, notes, and snippets.

@daltonclaybrook
Last active June 15, 2021 23:48
Show Gist options
  • Save daltonclaybrook/34a2e9f41ba9891d6196ff7ca7a8c8c0 to your computer and use it in GitHub Desktop.
Save daltonclaybrook/34a2e9f41ba9891d6196ff7ca7a8c8c0 to your computer and use it in GitHub Desktop.
import Foundation
private enum TimeoutResult<T> {
case success(T)
case timeout
}
struct TimeoutError: Error {}
/// Run an arbitrary async task that is cancelled after a provided timeout interval
func withTimeout<T>(_ timeout: TimeInterval, task: @escaping () async throws -> T) async throws -> T {
try await withThrowingTaskGroup(of: TimeoutResult<T>.self) { group -> T in
group.async {
let value = try await task()
return .success(value)
}
group.async {
let microseconds = UInt64(timeout * 1_000)
await Task.sleep(NSEC_PER_MSEC * microseconds)
return .timeout
}
defer { group.cancelAll() }
switch try await group.next()! {
case .success(let value):
return value
case .timeout:
throw TimeoutError()
}
}
}
func fetchWithTimeout(from url: URL, timeout: TimeInterval) async throws {
let (data, response) = try await withTimeout(10.0) {
try await URLSession.shared.data(from: url, delegate: nil)
}
// do stuff
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment