Error when downloading files with multiple background urlsession

Hi,

I am trying to download multiple files in background (using multiple background urlsession). I initiate the download on click of a button and push the app to background where the download should happen.

I am getting the following error:

Error Domain=NSCocoaErrorDomain Code=4 "“CFNetworkDownload_EYp3BT.tmp” couldn’t be moved to “Documents” because either the former doesn’t exist, or the folder containing the latter doesn’t exist." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/85AEEB4F-1512-4C0C-8B04-C9C73634CC49/Library/Caches/com.apple.nsurlsessiond/Downloads/com.mycompany.DownloadMultipleFilesTestApp/CFNetworkDownload_EYp3BT.tmp, NSUserStringVariant=(\n Move\n), NSDestinationFilePath=/var/mobile/Containers/Data/Application/85AEEB4F-1512-4C0C-8B04-C9C73634CC49/Documents/file-441966.pdf, NSFilePath=/private/var/mobile/Containers/Data/Application/85AEEB4F-1512-4C0C-8B04-C9C73634CC49/Library/Caches/com.apple.nsurlsessiond/Downloads/com.mycompany.DownloadMultipleFilesTestApp/CFNetworkDownload_EYp3BT.tmp, NSUnderlyingError=0x28155f900 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

In my sample code attached here i am trying with 500 background urlsession (one download task per each url session)

I have implemented the required methods:

application(_:handleEventsForBackgroundURLSession:completionHandler)

and

urlSessionDidFinishEvents forBackgroundURLSession:)

I have found that the error happens because of two callbacks to


urlSession(_:downloadTask:didFinishDownloadingTo:)

where i move the file from temporary location to a location in my app's documents directory.

The first time the file is present at the location, but for the second callback (with same urlsession id, task id and location values) to urlSession(_:downloadTask:didFinishDownloadingTo:) the file isnt present there and so the move fails.

Can someone please explain this erratic behaviour ? Is this a known issue with URLSession ?

For a repro, you can use the code attached above, test on a physical device without running app from xcode ie launch the app from phone's home screen, click on the download button and send the app to background. Check logs in the console app on mac

Test environment:

iPhone 8plus with iOS 16.7.8

Answered by DTS Engineer in 791744022
i am trying with 500 background urlsession (one download task per each url session)

Say what? You’re creating 500 background sessions!?! That’s… to put it mildly… suboptimal.

Session objects are relatively heavyweight. Most apps should only create a few. Specifically, using a new session for each task is poor form because it prevents connection reuse.

Background session objects are even ‘heavier’. Most apps can get away with just one. In some limited situations it might make sense to create a few. Creating 500 is completely beyond the pale.

Now, you could argue that URLSession should handle this better, and in that case you might file a bug about this. However, I wouldn’t be surprise if the resolution of that bug were to be for us to cap on the number of background sessions you create |-:

Share and Enjoy

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

i am trying with 500 background urlsession (one download task per each url session)

Say what? You’re creating 500 background sessions!?! That’s… to put it mildly… suboptimal.

Session objects are relatively heavyweight. Most apps should only create a few. Specifically, using a new session for each task is poor form because it prevents connection reuse.

Background session objects are even ‘heavier’. Most apps can get away with just one. In some limited situations it might make sense to create a few. Creating 500 is completely beyond the pale.

Now, you could argue that URLSession should handle this better, and in that case you might file a bug about this. However, I wouldn’t be surprise if the resolution of that bug were to be for us to cap on the number of background sessions you create |-:

Share and Enjoy

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

Thanks a lot for your prompt response here. :)

Say what? You’re creating 500 background sessions!?! That’s… to put it mildly… suboptimal.

We did go through the "factoids" you had mentioned here and that was indeed insightful. These high number of urlsession instances are created by the developers who make use of SAP Cloud Platform SDK for their iOS app development. We can surely inform them about such recommendations but as SDK, we really don't have any control on this aspect.

Most apps can get away with just one. In some limited situations it might make sense to create a few.

For most of the simple apps, a single instance can be used Agreed. But for larger/complicated enterprise apps, developers may end up creating a few. What would be a safe number of background urlsession instances (x) that an app could create and work with, without running into such issues from iOS ? x < 5?, x < 10?

Now, you could argue that URLSession should handle this better, and in that case you might file a bug about this

IMHO, an exception which mentions that resc limit has been exceeded might have been better than the current behavior where multiple didFinishDownloadingTo callbacks for a given session id, task id and file is noticed. We have already filed a bug with id : FB13956181

we really don't have any control on this aspect.

Right. Apple has the same problem. However, IMO it’s not worth hunting bugs that only show up when the developer creates hundreds of background sessions. That’s not using the API appropriately.

What would be a safe number of background urlsession instances (x) that an app could create and work with

Less than 10 is definitely fine. More than a hundred is definitely bad. A reasonable limit lies somewhere in the bottom half of that range.

We have already filed a bug with id : FB13956181

Thanks for filing that.

Share and Enjoy

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

Error when downloading files with multiple background urlsession
 
 
Q