Deduplicated URLRequests

Hi,

In the session it's mentioned that requests are being deduplicated when a new request with the same method, url is being sent in the same session while another one is still being performed. I never heard of it before and used to implement that manually in different apps. Is it a new feature of URLSession or should be expect this before? Does anybody know?

Best,

Karl

I too would like more detail on this as it sounds like a great feature!

But, I can't get the code snippet shown at 11:26 in the video Efficiency awaits: Background tasks in SwiftUI to work? Running this:

    let config = URLSessionConfiguration.background(withIdentifier: "isStormy")
    config.sessionSendsLaunchEvents = true
    let session = URLSession(configuration: config)
     
    let response = await withTaskCancellationHandler {
      try? await session.data(for: request)
    } onCancel: {
      let task = session.downloadTask(with: request)
      task.resume()
    }

the line try? await session.data(for: request) throws the following exception:

Completion handler blocks are not supported in background sessions. Use a delegate instead.

Using Xcode 14.1 and a iOS 16.1 simulator.

Creating the session with a delegate (like let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)) doesn't help, same exception.

Has anyone got this to work?

the line try? await session.data(for: request) throws the following exception

Yep. That’s a bug in the presentation [1]. The Swift async API to URLSession is layered on top of the convenience API, the one that uses completion handlers, and that’s not supported in background sessions. So, the point of this discussion is valid — it’s reasonable to start a request as a data task and, if you transition to the background, cancel that and retry it as a download task — but the mechanics are substantially more complicated.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, if you’re feeling generous, you could call it an over simplification (-:

Thank you for your response @eskimo!

Just so I understand you correctly:

  1. Is it possible to achieve request deduplication using two URLSession instances? If not, I guess the withTaskCancellationHandler was also part of the over simplification?
  2. So we should instead launch a data task and have the delegate "catch" the cancel error and retry it as a download task?
  3. You mentioned "cancel that and retry it as a download task". Are we responsible for canceling the tasks when the app transitions to the background, or can we rely on the system doing that?

All the best, Jonas

Is it possible to achieve request deduplication using two URLSession instances?

Just so we’re clear, the referenced WWDC presentation says:

URLSession will deduplicate any in-process requests under the hood.

I’ve no idea what the speaker was trying to convey there. URLSession can cache responses but AFAIK it will not deduplicate inflight requests.

So we should instead launch a data task and have the delegate "catch" the cancel error and retry it as a download task?

The exact mechanics of how you do this are up to you. In a Swift concurrency world you could implement it by catching the error. Alternatively, you could just cancel one task and then start the download immediately. That simplifies the startup at the cost of making the commit more complex.

You mentioned "cancel that and retry it as a download task". Are we responsible for canceling the tasks when the app transitions to the background, or can we rely on the system doing that?

The tasks in a standard session will fail if your app gets suspended. Exactly how they fail is a complex question. IMO you’d be better off taking control of this yourself by explicitly cancelling them.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Deduplicated URLRequests
 
 
Q