NSURLSessionDownloadTask stalls in background, slow to recover in foreground

I am creating a background session using this code...


        let configuration = URLSessionConfiguration.background(withIdentifier: UUID().uuidString)
        configuration.sessionSendsLaunchEvents = true
        configuration.isDiscretionary = false
        self.session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: nil)


...and download tasks using this code:


        let downloadTask = self.session.downloadTask(with: request as URLRequest)       
        downloadTask.resume()


My request objects looks like this:


        let request = NSMutableURLRequest(url: someURL)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        do {
            try request.httpBody = JSONSerialization.data(withJSONObject: someDictionary, options: JSONSerialization.WritingOptions())
        } catch let error as NSError {
            // logging calls
        }


The resources being download are ~20MB zip files.


I can run four concurrent downloads in the foreground with no issue. All expected delegate methods are called and the transfers complete at a normal speed.


The problem that I am seeing is that if I start the downloads in the foreground and then hit the home button the downloads will sometimes stall. I have tried keeping the device awake and the network spun up for an hour and the transfers still don't complete in the background. Additionally, when I bring the app back to the foreground the transfers do not immediately start again. If I let the app sit in the foreground for ~4 minutes, they will wake up and start working again. They resume at the percentage complete they were at when the app went into the background, and will transfer at normal speed until complete. At no time are there any errors, and the transfer is ultimately successful. It just "goes away" while in the background, and is very slow to resume when the app comes back to the foreground.


I am testing on an iPhone 6 running iOS 10. I am not connected to Xcode or external power and I am launching the app cold. I can reproduce the issue over both WiFi and cellular connections. I have deleted the app and reloaded it multiple times.

I am having trouble tracking this down because approximately 20% of the time it works fine. I have not found any particular set of variables that causes it to consistenly work or fail. It seems to happen more frequently when multiple downloads are occuring, and in that situation all of the downloads exhibit the behavior described above.

Any guidance would be greatly appreciated!

Matt

Hello,


I have the same issue. I download more than 40 files of sizes between 50 MB and 1GB. I tested both with the app in foreground and in background. The download is really slow (a lot of delay between downloads). It happens to wait many minutes with app in foreground (I just stay & pray to see any progress of any download..) until the OS decides to start a new download. All tests were done with WIFI available and working & full battery. All downloads will finally complete .. but I need to be very patient & wait. I use the 'discretionary' flag set on false & start all the downloads from the app while it is in foreground.


This issue does reproduce very easy by starting about 40 downloads of the specified sizes (always also with phone in changer).

Apple please help.


Thank you,

Mihai

Quote from https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background#3038438

" When the system resumes or relaunches your app, it uses a rate limiter to prevent abuse of background downloads. When your app starts a new download task while in the background, the task doesn't begin until the delay expires. The delay increases each time the system resumes or relaunches your app. As a result, if your app starts a single background download, gets resumed when the download completes, and then starts a new download, it will greatly increase the delay. Instead, use a small number of background sessions — ideally just one — and use these sessions to start many download tasks at once. This allows the system to perform multiple downloads at once, and resume your app when they have completed. Keep in mind, though, that each task has its own overhead. If you find you need to launch thousands of download tasks, change your design to perform fewer, larger transfers. Note The delay is reset to 0 whenever the user brings your app to the foreground. It also resets if the delay period elapses without the system resuming or relaunching your app."

So you want a single session that launches (aka USUrlsesson.downloadtask(...).resume()) as many download tasks simultaneously as possible. If you just issue a single download task at a time, then your 2nd, and 3rd download tasks would be delayed by OS system gradually, at last your download task stops.

NSURLSessionDownloadTask stalls in background, slow to recover in foreground
 
 
Q