background multitasking upload

hi,I have some question when i use background session to upload

if i upload a big file with backgroundConfiguration and make the app into background ,the example1 delegate method will be called back like this

example1

applicationDidEnterBackground

bytesSent: 32768, totoalBytesSent 11960320 ,totalBytesExpectedToSend: 52428800
bytesSent: 32768, totoalBytesSent 11993088 ,totalBytesExpectedToSend: 52428800

application:handleEventsForBackgroundURLSession:completionHandler:

request = 3335 URLSession:task:didCompleteWithError:

URLSessionDidFinishEventsForBackgroundURLSession:

everything is ok

example2:

but when i use multitasking upload,i will add them to an operationArray and i will take five tasks from the queue,when a task have completed and i will take a new task from operationArray to resume ,the delegate method will be called back linke this

applicationDidEnterBackground

bytesSent: 32768, totoalBytesSent 3211264 ,totalBytesExpectedToSend: 5242880
...
bytesSent: 32768, totoalBytesSent 4947968 ,totalBytesExpectedToSend: 5242880


application:handleEventsForBackgroundURLSession:completionHandler:

request = 3363 URLSession:task:didCompleteWithError:
request = 3361 URLSession:task:didCompleteWithError:
request = 3365 URLSession:task:didCompleteWithError:

[task][3367]take  task[3367] from array

request = 3362 URLSession:task:didCompleteWithError:
request = 3366 URLSession:task:didCompleteWithError:

URLSessionDidFinishEventsForBackgroundURLSession:

[task][3368]take task [3368] from array
[task][3369]take task[3369] from array
[task][3364]take task[3364] from array
[task][3370]take task[3370] from array

bytesSent: 32768, totoalBytesSent 32768 ,totalBytesExpectedToSend: 5242880
...
bytesSent: 32768, totoalBytesSent 1638400 ,totalBytesExpectedToSend: 5242880

application:handleEventsForBackgroundURLSession:completionHandler:

request = 3367 URLSession:task:didCompleteWithError:
request = 3368 URLSession:task:didCompleteWithError:


URLSessionDidFinishEventsForBackgroundURLSession:

bytesSent: 32768, totoalBytesSent 32768 ,totalBytesExpectedToSend: 5242880
...
bytesSent: 32768, totoalBytesSent 1802240 ,totalBytesExpectedToSend: 5242880

application:handleEventsForBackgroundURLSession:completionHandler:

request = 3370 URLSession:task:didCompleteWithError:
request = 3369 URLSession:task:didCompleteWithError:
request = 3364 URLSession:task:didCompleteWithError:

URLSessionDidFinishEventsForBackgroundURLSession:

the example2 is different from example1 is that example2 have progress calll back ,should it have progress call back when a task was completed in background?



there are alse have some strange logs , the URLSession:task:didCompleteWithError will called back after URLSessionDidFinishEventsForBackgroundURLSession: like this:


[task][3339]take task from array 

applicationDidEnterBackground 

bytesSent: 32768, totoalBytesSent 32768 ,totalBytesExpectedToSend: 5242880
...
bytesSent: 32768, totoalBytesSent 1998848 ,totalBytesExpectedToSend: 5242880

application:handleEventsForBackgroundURLSession:completionHandler:

URLSessionDidFinishEventsForBackgroundURLSession:

request = 3339 URLSession:task:didCompleteWithError:
Post not yet marked as solved Up vote post of karisli Down vote post of karisli
3.3k views

Replies

should it have progress call back when a task was completed in background?

In general, a background session won’t resume (or relaunch) your app in the background solely to give it progress callbacks. However, if you’re missing the progress events after being brought to the front, it’s possible that you’re being affected bug the bug discussed on this thread.

but when i use multitasking upload, i will add them to an

operationArray
and i will take five tasks from the queue, when a task have completed and i will take a new task from
operationArray
to resume

How many tasks are you dealing with here? The approach you’ve described in not one we recommend because of the resume rate limiter. See the following posts for more:

In general, it’s better to present all of your uploads to the session and let it deal with them. However, that’s only viable if there’s a reasonable number of uploads.

Share and Enjoy

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

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

thank you for the reply.


i thought about rate limiter ,The reason why I did this because when I enter the background after a long time and then enter the foreground again,I can continue to upload.


this is my case:when i get a file path,i will do like this:


1.first i will init a request ,wait it return a upload id.

2.then i need to divide a big file(Maximum size for big file is 50 TB)into several small files(The size of each file is 5MB)to upload.I have a custom queue ,i will put these operations into this custome Queue and start a maximum of 5 tasks at a time.

3.when all tasks completed,i will send a complete request to complete this transfer.


but I have some problems:i test upload a 50MB file,it means that i will have a post request to init and 10 tasks to upload ,finally i need to send a post request to complete.


scenario 1:

1.when the app begin to run ,i click the beginupload button.

2. and then i click the home to make my app enter background after a few seconds.

result: it will output logs and start new task when a task have completed,but it would stop suddenly after a few seconds, and stop output any logs,this situation happened frequently but not necessarily.


scenario 2:

1. when the app start to run ,i click the beginupload button

2. i will wait all tasks complete and i click the beginUpload button once again to start a new transfer.

3. then i click the home to make the app enter background after a few seconds.


result: all tasks will be completed in background, it usually comes with a situation that the upload progress will be called back but i have not restart my app until all task completed.


I have tested it many times,and i get a conclusion:once i have completed a upload,then i start a new transfer and make the app enter background,,all task always can be completed,but it usually comes with a situation that the upload progress will called back,but i have not restarted my app until all task completed. If I upload it for the first time it always will stop and failed.


Looking forward to your reply

I’m not entirely sure I understand what you’re saying here, but I want to first make sure you’re testing this correctly. Check out my Testing Background Session Code pinned post.

With regards your high-level issue, you wrote:

1. first i will init a request ,wait it return a upload id.

I would do this request using a standard

URLSession
, using a
UIApplication
background task to prevent the app from being suspended while that runs. This ensures that the request either completes or fails promptly, avoiding the need for a (potential) background session resume between steps 1 and 2.

2. then i need to divide a big file(Maximum size for big file is 50 TB) into several small files (The size of each file is 5MB) to upload.I have a custom queue, i will put these operations into this custom Queue and start a maximum of 5 tasks at a time.

How are you managing this queue? In memory? Or on disk?

If it’s in memory then you’re going to need extra code because it’s possible that the system might terminate your app (and thus lose your memory state) while it’s suspended in the background. If that happens it’ll relaunch your app when the current batch of tasks complete, and then you need to work out how to continue.

Also, is there any flexibility on the file size? 5 MB is too small.

Finally, running 5 tasks at a time is way too few. Imagine you have to upload 1 GB. Each upload cycle will upload 25 M, meaning you need to be resumed in the background 40 times. The resume rate limiter will definitely be punishing you at that point.

In contrast, if you upped the file size to 20 MB and the task count to 50 — and these are both reasonable numbers — you could upload the whole file in one cycle.

3. when all tasks completed, i will send a complete request to complete this transfer.

This is another situation where you should explore using a standard session.

Share and Enjoy

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

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

Thank you very much for your reply and I'm sorry I didn't make myself clear

for your questions:

1. i run my app from xcode ,Do you think that's a reason that My app is still printing progress information after enter the background

(it seems to print lot of progress information before the appDelegate method

application:handleEventsForBackgroundURLSession:completionHandler:

calleback every time).


2. How are you managing this queue? In memory? Or on disk?

i managed queue in memory,According to your advice, I will consider to save queue in disk.

i run my app from xcode, Do you think that's a reason that my app is still printing progress information after enter the background

Yes. When you run from Xcode, you’re running with the debugger attached. Having the debugger attached prevents your app from being suspended when it’s moved to the background. As your app isn’t suspended, you continue getting progress events.

Share and Enjoy

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

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

i get it,thank you for your help