Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS foreground or background #454

Open
dineshpote26 opened this issue Feb 7, 2025 · 4 comments
Open

iOS foreground or background #454

dineshpote26 opened this issue Feb 7, 2025 · 4 comments

Comments

@dineshpote26
Copy link

Issue:
I am facing an issue with uploading videos to the server. In my queue, there are 100 pending records, and when the app is open, the queue processes them very quickly.

Queue Configuration:

tq.maxConcurrent = 2; // No more than 2 tasks active at any one time
tq.maxConcurrentByHost = 2; // No more than 2 tasks talking to the same host at the same time
tq.maxConcurrentByGroup = 2; // Limit concurrent tasks by group

Problem:
When the app is running in the foreground or background (i.e., when switching to other apps), the queue responds slowly. The requests hit the server after 2–3 minutes, and sometimes it takes up to 5 minutes.

This issue occurs mostly on iOS.

Question:

Are there any suggestions or workarounds to improve the upload performance in the background, especially for iOS?

@declaratived
Copy link

declaratived commented Feb 8, 2025

I observe the same issue as @dineshpote26

Have implemented the background_downloader to upload videos that my app records in background. I am using on iOS18. The app works perfectly fine when the app is open. However, whenever I switch to another app or when phone is locked, the background_downloader stops sending requests to server even though there are many tasks pending in its queue.

From what I understand, I may have to write an iOS BGTaskScheduler to keep calling the background_downloader. Is my understanding correct? Appreciate any clarification, guidance, or reference implementations where background_downloader has been used for true background activity in iOS. @781flyingdutchman appreciate if you can look into this and advise.

Thanks

@781flyingdutchman
Copy link
Owner

Hi, I think you're using a TaskQueue and per the docs that mechanism does not work when your app is in the background. Use a HoldingQueue instead. That should work in iOS though it is definitely not as fast as when the app is in the foreground, as the OS manages how much resource is given to the background queues. The fastest background operations will be when you don't use a separate queue at all.

@dineshpote26
Copy link
Author

I am using HoldingQueue as shown below:

try {
bg.FileDownloader().configure(globalConfig: [
(bg.Config.holdingQueue, (5, 5, 5)),
(bg.Config.runInForeground, bg.Config.always),
(bg.Config.requestTimeout, const Duration(seconds: 600)),
], androidConfig: [
(bg.Config.useCacheDir, bg.Config.whenAble),
], iOSConfig: [
(bg.Config.localize, {'Cancel': 'StopIt'}),
]).then((result) => debugPrint('Configuration result = $result'));
}catch(e){
print('bg.FileDownloader().configure ${e.toString()}');
}

The fastest background operations will be when you don't use a separate queue at all. Does this mean I should remove this line?
bg.Config.holdingQueue, (5, 5, 5)),

If I’m not using any queue, will maxConcurrent apply to the entire queue automatically ie 100 in queue then 100?

@781flyingdutchman
Copy link
Owner

If your server allows, it is best to not use any maxConcurrent limitation, and let the OS and server negotiate what can be done in parallel. That means no TaskQueue and no HoldingQueue configuration either, so yes, remove the bolded line and remove any reference to a TaskQueue.

A bit more detail:

  • TaskQueue is a Dart object and therefore won't 'run' when the app is suspended (both iOS and Android do this after some time when the app moves to the background, i.e. when it is not the foreground app being used). That means that any tasks still waiting in the TaskQueue won't get enqueued when the app is suspended. The main purpose of the TaskQueue is to pace the rate at which tasks are enqueued to the downloader, so it is very helpful to use it when you have many tasks you enqueue in a short period of time. In that scenario, you do not set any maxConcurrent limit
  • HoldingQueue was created to address the suspended app issue: it lives in the native side (Android or iOS) and will enqueue the next task when a previous task finishes, in the plugin, so it will run also when the app is suspended
  • On iOS specifically, the OS strongly prefers enqueueing all tasks related to a URLSession together. The HoldingQueue does not do this: it adds tasks to the URLSession one by one - every time a task finishes it adds another, so that it can adhere to maxConcurrent. iOS penalizes this by reducing the resource allocated to the URLSession, especially for tasks added when the app is suspended, so while this works, it will not lead to high performance/throughput. To be clear, this is working as intended as far as iOS is concerned, in that they aggressively manage background activity.
  • While iOS has a httpMaximumConnectionsPerHost option in URLSession, in practice is does not work, as most modern connections use HTTP2 which is specifically designed to allow multiple http sessions over a single connection. That is therefore not a reliable way to limit the number of tasks running simultaneously, and is not how I have implemented maxConcurrent.
  • iOS and Android both manage multiple simultaneous uploads/downloads quite well out of the box, so I suggest testing if removing the queues works - it may well be the best way to run this.

Hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants