Does Task cancellation propagate to URLSessionTasks?

If I have a Swift Task like this:

let task = Task {
  let (data, response) = try await URLSession.shared.data(from: URL(string: "https://some-image-url.com")!)
  // ...
}

And then I do task.cancel(), does URLSession automatically cancel the URLSessionTask as well? It seems careless to assume that the URLSessionTask is cancelled too, but I can't find any documentation on this matter. However, if the URLSessionTask is not automatically cancelled, then I'm forced to use the closure-based URLSession.dataTask(with:,completionHandler:) to get a reference to the URLSessionTask, and then to also call something like dataTask.cancel() on top of task.cancel(), which is somewhat odd.

3 Likes

Yes. Consider this test code:

import Foundation

func main() async {
    let t = Task {
        do {
            print("\(Date.now): task will start")
            let url = URL(string: "https://postman-echo.com/delay/10")!
            let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
            let (data, response) = try await URLSession.shared.data(for: request)
            print("\(Date.now): task did complete, response: \(response), data: \(data)")
        } catch {
            print("\(Date.now): task did error")
        }
    }
    if true {
        try? await Task.sleep(for: .seconds(1))
        print("\(Date.now): will cancel task")
        t.cancel()
        print("\(Date.now): did cancel task")
    }
    print("\(Date.now): waiting")
    try? await Task.sleep(for: .seconds(60))
}

await main()

It prints:

2023-05-18 08:18:52 +0000: task will start
2023-05-18 08:18:53 +0000: will cancel task
2023-05-18 08:18:53 +0000: did cancel task
2023-05-18 08:18:53 +0000: waiting
2023-05-18 08:18:53 +0000: task did error

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

4 Likes