Request timeout when app is in background

Hi,


We have an enterprise application and we are trying to download couple of files when application is in background.

We have used URLSession to execute the downloadTask. We use timeout value of 15 mins for each file. BackgroundFetch is enabled for the app.

Now we are facing problem sometimes when application tries to download file in background which receives request timeout.

In the ipa logs we can see that download has been started (that means code to download file has been executed) However we do not receive any chunks of data back. and after waiting for timeout value 15 mins, we get request timeout error in delegate method -

didCompleteWithError:
Mean while our apache server do not receive request for download.

This do not happen every time. We also checked there is no latency in our network or any network delays.


We came across an observation that as soon as we connect device to the charger (device battery should be > 10%), download starts immediately in background reliably.


So we thought that iOS might have some threshold battery value above which it gives priority to background tasks. But that was not true!

We had faced this issue even when our client's iPad battery was > 90% (charger not connected)


The files we are downloading are with size varying from 100kbs - 50mb

We have received request timeout for small files also of 250kbs


It only works perfectly in background when device is connected to charger OR application is in foreground mode.


We are aware that background tasks should not be taken granted and should be performed for time insensitive tasks but wanted to know more about this behaviour of iOS where it performs downloading instantly as soon as charger is connected.


While researching more we came across a link which explains similar scenario throughly.

https://topologyeyewear.github.io/engineering-blog/2017/11/20/background_transfer/

We are using below API calls.


func backgroundUrlSessionWithIdentifier(_ identifier: String) -> URLSession {
        let config = URLSessionConfiguration.background(withIdentifier: "\(identifier)")
        config.timeoutIntervalForResource = 900.00
        config.isDiscretionary = false
        config.sessionSendsLaunchEvents = true
        print("Downloading start progress NetworkManager ::  \(#function)")
        return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
    }


        let session = backgroundUrlSessionWithIdentifier(identifier)
        let request = URLRequest(url: url)
        let donwloadTask = session.downloadTask(with: request)
        donwloadTask?.resume()

Replies

If you set the resource timeout for a background transfer to 15 minutes then it’s very likely that you’ll see timeout errors. I generally recommend that you not set the resource timeout to anything shorter than a day [1].

It only works perfectly in background when device is connected to charger OR application is in foreground mode.

The exact algorithm used by the background session to schedule requests is not documented — it has changed in the past and it’s likely to change in the future — but it’s not uncommon for requests to be delayed until the device has both mains power and Wi-Fi.

Also, one of the tweaks we made shortly after introducing background sessions was that we boost priority of requests if the app is in the foreground. In this case a watched pot does actually boil faster (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] The only exception to this is when you’re requesting a resource that won’t be useful if you receive it after a certain deadline.