Background NSURLSession when uploads must be prompt

I have an app with which users take photos and upload them in batches. It's used often on older devices, in areas with less than ideal network, and for durations of a full workday - so often the device has low power.

The current implementation of uploads uses an NSURLSession configured for the foreground, and as a result my users are used to having to keep the app in the foreground while an upload completes. However, these uploads are big and connectivity is often low, so this takes a long time - often users are stuck waiting with the app foregrounded for 15 minutes or so while the upload completes.

So, I created a build which uses an NSURLSession configured for the background. In the ideal case, users could start the upload, put the device in their pocket and continue their workday, and the next time they open their device it will be complete.

For some users this ideal case has come true. However, for others, the uploads sit in progress for an indeterminate amount of time, making no progress. My suspicion is that this is because the OS is deferring them until a time when network and power is more available. However, my users are using work devices at a work location - reliable power and network might never be available. Being able to background the app and continue working is valuable for these users, but having the upload complete promptly is essential for them.

My questions are:

  • Is it true that background configured NSURLSessions will defer network requests when connectivity or power is low, even if discretionary = NO? Is the exact behavior for when requests will be attempted in the background documented?
  • Is there a way to reliably test background configured NSURLSessions in XCode? I've attempted throttling my connection with Charles Proxy, and using my device in Low Power Mode, but I'm unable to reproduce the request stalling behavior my users are experiencing in the wild.
  • Is there a way to create an NSURLSession that will muscle through difficult or inefficient uploads in the background, with the same reliability as a foreground session?
  • If not, what is Apple's recommended approach to situations like mine? I've considered queueing both a background and foreground upload, and cancelling the other once one completes, but this seems disrespectful to the user's resources.
  • Will setting timeoutIntervalForResource to a lower value cause the OS to more aggressively attempt uploads? Or simply to throw an error sooner? I want the OS to give the upload a long time to complete, but I also want it to attempt it right away.

Thanks for any information!

Is it true that background configured NSURLSessions will defer network requests when connectivity or power is low, even if discretionary = NO?

Yes. Background session transfers are (effectively) always considered discretionary.

Is the exact behavior for when requests will be attempted in the background documented?

No. The actual behaviour is an implementation detail that’s unlikely to ever be documentation because a) it’s staggeringly complicated, and b) it changes regularly.

Is there a way to reliably test background configured NSURLSessions in Xcode?

No, at least not for any reasonable definition of the phrase “in Xcode”. I have a post about this somewhere… lemme go look… oh, here we go: Testing Background Session Code.

I'm unable to reproduce the request stalling behavior my users are experiencing in the wild.

That’s not a question (-: But, yeah, that’s not surprising. I don’t use the phrase “staggeringly complicated” lightly (-:

Is there a way to create an NSURLSession that will muscle through difficult or inefficient uploads in the background, with the same reliability as a foreground session?

No. That would burn through the user’s battery.

If not, what is Apple's recommended approach to situations like mine?

My #1 suggestion is that you support resumable uploads. That makes the best use of what bandwidth you get.

I have a bunch of other general advice in Moving to Fewer, Larger Transfers.

One of the options it suggests is background processing tasks. My experience is that those are run with some regularity — typically overnight when the user charges their phone — and they make a good backstop for your uploads. That is, if your app is resumed or relaunched to run your background processing task, you can check on the state of your background session work and, if necessary, reschedule it in a standard session.

Will setting timeoutIntervalForResource to a lower value cause the OS to more aggressively attempt uploads?

No [1].

Or simply to throw an error sooner?

Yes [1].

Share and Enjoy

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

[1] So, I have to apply a caveat here. As I mentioned above, we’re talking about implementation details here, so this could be a factor either now, in previous releases, or in The Future™. My point is that you shouldn’t set an artificial timeout in an attempt to game the algorithm.

Background NSURLSession when uploads must be prompt
 
 
Q