Is ftp or http a preferable protocol for large file downloads in ios

We have an enterprise ios application written in swift.


We are attempting to download files at night onto an ipad , while the device is in background mode.


We are using httpurlconnection class running on a background thread.

We have our devices plugged into a power source.

We have over 10% failure rate whereas the download does not finish and we need to request again.


Has anyone experienced similar issues ?

Would we have better results with ftp?


thanks.

Replies

Is ftp or http a preferable protocol for large file downloads in ios

HTTP. Don’t use FTP for anything. See my On FTP post for an explanation as to why.

We are using httpurlconnection class running on a background thread.

httpurlconnection
isn’t an Apple API. Are you perhaps referring to
NSURLConnection
? If so, that’s a legacy API that I recommend you avoid. It certainly isn’t able to run large downloads in the background.

The droid you’re looking for here is

NSURLSession
background sessions. See Downloading Files in the Background for more info.

Share and Enjoy

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

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

Thank you kindly Quinn "The Eskimo" for the response.


Yes we are using NSURLSession with https currently.


The reason why we were exploring alternatives is because our model is to download 10 files nightly to the device and we are getting enough failures to finish that we thought there might be a better way to do this.


We are using the APNS service to wake up the app with a payload which tells it to go get those files using the NSURLSession class running in a background thread.


The files are served from an apache file server and range from 10mg to 1.4gig.


Is this approach ideal for the scenario?


thanks.

Just to set the stage here, your overall target (a nighttime download of 10 resources that range between 10 MB and 1.4 GB) is pretty reasonable.

We are using the APNS service to wake up the app with a payload which tells it to go get those files using the

NSURLSession
class running in a background thread.

The thread you use here is irrelevant. When your process gets suspended in the background all your threads stop running. The salient point is whether you’re using a background session. Are you?

Share and Enjoy

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

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

Yes a background session is started as a result of the pushkit notification.

The app would either be in sleep mode or non-instantiated because these notifications are sent off-hours (e.g. 2AM)


We were not sure if we would get better results with ftp than http protocol was the original question and it seems that http is the recommended way to go as ftp is being deprecated and that there is no reliability / speed advantage as well.


We've had numerous issues with this process being reliable in a way that we would like it.

The failures are mostly that one of the 10 files download fails as a result of the killed background session.

We would like to have a fail-safe download process that can auto-correct from this scenario.

We would ultimately like to support download of up to 5-6 gb files


Q: Any suggestions as to better ways to handle this or feedback that the general approach is sound but certain things to watch out for/handle?

e.g. Would it better to zip up all the files in one package and download one file or download 10 individual files?

Yes a background session …

Cool.

We were not sure if we would get better results with ftp than http protocol was the original question …

Part of my confusion here stems from the fact that background sessions don’t support FTP; they only support

http
and
https
URLs.

Any suggestions as to better ways to handle this …

I have a lot of general suggestions on that front. If you navigate to the Core OS > Networking topic area page, you’ll find a bunch of posts about this sort of thing pinned on the right.

I’d also like to offer some specific suggestions but to do that I need more information about your situation. Let’s start with this:

The failures are mostly that one of the 10 files download fails as a result of the killed background session.

What do you mean by “killed” in this context?

Share and Enjoy

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

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

By "Killed" i meant to say we start a background session using urlSession to download a file from an apache file

server and the process does not finish. We check the status in the morning after the user instantiates the app and

need to redownload because it did not finish overnight.

If you relaunch the app do you get the completion delegate callback for the request (

-URLSession:task:didCompleteWithError:
)? If so, did it complete successfully? Or fail? And if it failed, what error did you get?

If you don’t get the completion delegate callback, call

-getTasksWithCompletionHandler:
to see if the task is still in the list of tasks known to the session.

Share and Enjoy

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

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

The background error we see is 1001 (request timeout). I know you had recommended setting the timeout to 1 day.

The default resource timeout is 7 days, and I generally recommend that you leave that as it is unless you have a specific reason to change it.

The background error we see is 1001 (request timeout). I know you had recommended setting the timeout to 1 day.

There’s two possibilities here:

  • You hit the request timeout for a non-retryable request (A).

  • You hit the resource timeout (B).

I’m thinking that A doesn’t apply because you doing a download (a GET). Is that still the case? If you start doing non-retrying things (like a PUT or a POST), you have to worry about the request timeout.

With regards B, the way you’ve described things it sounds like the task failed before the resource timeout hit. That is, you have a sequence like:

  1. Sometime during the day, you started a task with a resource timeout of 1 day.

  2. You came in the next morning to find the request has failed.

That’d be weird, because the one day resource timeout should only affect you when you get to the time of day for step 1.

Regardless, the first step in my investigation would be to use a packet trace to see what’s happening on the ‘wire’. For example, I’ve seen situations where a retryable request would never complete because:

  • It was not resumable.

  • The throughput was so slow that iOS kept deferring the task.

  • Each time it was deferred, it had to start from the beginning because it couldn’t resume where it left off.

Share and Enjoy

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

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

Hi Quinn,


We are drilling down based on your suggestions .


Can you please confirm ( or not ) that is recommended to have no request timeout when downloading using the background session/thread?


If true, would this apply when downloading in the foreground?


thanks

is [it] recommended to have no request timeout when downloading using the background session/thread?

There are always timeouts, it’s just a question of whether you override the defaults or not. To summarise:

  • The request timeout applies to traffic on a specific connection. If no data has been transferred within that time, the connection fails (whether that causes the task to fail depends on whether the request is retryable). The current default is 60 seconds, and you can override it for all requests in a session using

    timeoutIntervalForRequest
    , or on a specific request using its
    timeoutInternval
    property.
  • The response timeout applies to the task as a whole. If the task can’t complete within that time, it fails. Typically this is only relevant for retryable requests, but it’s theoretically possible it could happen for a non-retryable request if it runs very slowly but never completely stalls. The current default is 7 days, and you can override it for all tasks in a session using

    timeoutIntervalForResource
    .

IMPORTANT The default timeout values mentioned above are not considered API. They have changed in the past and they may well change in the future. However, it’s unlikely that they’ll change to radically different values because that could cause binary compatibility problems.

Share and Enjoy

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

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