Build and execute queue of SessionDataTasks in the background?

I could really use some direction on the best approach for this. I have an app that needs to send a queue of API requests. I need these requests to complete even if the app moves to the background. One issue is that in some cases the data submitted for the API request could be dependent on the earlier in queue being parsed. So the I may need to inject a new value in the later requests based on what's returned in the earlier calls. So what would be the best approach for this? I assume background transfer service wouldn't work since I need to alter the tasks before they're sent? I just need to ensure that these requests are submitted as soon s possible. Any suggestions are greatly appreciated!

Replies

You’re correct that there are challenges in setting up a sequence of tasks in a background session where later tasks are dependent on earlier tasks. Specifically:

  • Sessions do not guarantee to execute tasks in order

  • Background sessions only resume (or relaunch) your app when all tasks in the session are done

  • Resuming after each request will cause problems; see NSURLSession’s Resume Rate Limiter for details

Whether there’s a viable solution depends on the pattern of your requests. If you have, for example, a set of requests A that are all independent, followed by a set of requests B that are all dependent on A but independent of each other, that should be fine. Submit A, get resumed when they all complete, then submit B.

One technique you can use here is to submit small requests to a standard session. Standard sessions work in the background as long as you can prevent your app from suspending. If you have a few requests that typically completely quickly, you can run them while keeping your app from suspending via a UIApplication background task. To continue the above example, if you need to run request C to check that all the work done by the requests in set A went OK, and request C typically runs quickly, you can run C in a standard session when you’re resumed after all of A are done, keep your app from suspending while C runs, then, when C is done, start B.

Share and Enjoy

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

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

Ok thank you very much for that thorough description. My original intent was to handle all requests with the same logic, but it sounds like I need to handle the request cases where the subsequent calls depend on earlier calls in a seperately configured NSURLSession? I've reviewed the background task documentation but I'm still not sure where the call should be made to beginBackgroundTaskWithExpirationHandler? Currently I have an NSOperation sublclass that builds and executes the NSURLSessionDataTask when that task completes I process the response, mark the operation as complete. The queue has it's maxConcurrentOperationCount set to 1 and each NSOperation that's added is dependant on the one before it. In my case, the cases where requests are truly dependant on earlier requests just need the API to return an id number before processing subsequent data.

I had a followup question for clarification:


I feel like maybe I'm over complicating things for my use cases...this is just a handful of small (100K tops) requests. I just need to ensure that they're queued and sent as soon as possible. If the device is offline or on a poor connection, they should keep retrying until they're successful with fairly liberal retry limit before bailing.

I feel like maybe I'm over complicating things for my use cases…

Perhaps, but it’s hard to say because this:

this is just a handful of small (100K tops) requests. I just need to ensure that they're queued and sent as soon as possible. If the device is offline or on a poor connection, they should keep retrying until they're successful with fairly liberal retry limit before bailing.

doesn’t talk about the dependencies between your requests. It’s those dependencies that make this tricky (if all of these requests were independent, you’d just drop them into an NSURLSession background session and be done).

So, can you expand the above to talk about dependencies?

Share and Enjoy

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

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