apache / cordova-plugin-file-transfer

Apache Cordova File Transfer Plugin
https://cordova.apache.org/
Apache License 2.0
595 stars 888 forks source link

Timeouts after downloading a lot of files (iOS) #260

Open elvisgraho opened 4 years ago

elvisgraho commented 4 years ago

Bug Report

Problem

When you download a lot (more than 200) of files (images) consecutively, NSMutableURLRequest gets stuck after 50+ successful requests (and a few requests after that), because of the connection timeout.

You can see when it starts to happen, because few connections will get slower and slower until eventually it will time out.

Possibly this link is related, idk.

As mentioned in the link above, [connection cancel] does nothing.

What is expected to happen?

No timeouts.

What does actually happen?

Timeouts.

Rewriting success call did not help but seem to improve a performance a little bit.

    // remove connection for activeTransfers
    @synchronized (command.activeTransfers) {
        [connection cancel];
        [command.activeTransfers removeObjectForKey:objectId];
        // remove background id task in case our upload was done in the background
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
        self.backgroundTaskID = UIBackgroundTaskInvalid;

        [self.command.commandDelegate sendPluginResult:result callbackId:callbackId];
    }

*Note that my JS code explicitly waits for [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; before sending next request.

sdkester commented 3 years ago

@elvisgraho We removed the cached response to improve the memory usage when transferring a lot of files.

CDVFileTransferDelegate* currentDelegate = command.activeTransfers[objectId];
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:currentDelegate.connection.currentRequest];
nunohorta commented 3 years ago

@elvisgraho are you doing multiple downloads at the same time?

@sdkester did you add that code after each transfer? I'm trying to workaround timeouts here too and I keep seeing errors about "Background task X, was created over 30 seconds ago..." so I think iOS is killing the tasks which then results in a file transfer timeoutt

elvisgraho commented 3 years ago

@nunohorta No. One download after another. "*Note that my JS code explicitly waits for [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; before sending next request."

"Background task X, was created over 30 seconds ago" issue is fixable when you set the request timeout in Objective-C code. The funny thing is, that the default timeout is 60 secs, but the max timeout for Background tasks is 30.

After that I'v got further Problems that are deeply rooted in iOS and deprecated HTTP client functions that are used in this plugin. The issue is that "[connection cancel];" does not actually cancel the connection. It is an asynchronous process that tells the low-level code to perform a cleanup. Once the cache gets full, it gets stuck.

What fixed the issue for me is:

  1. Ditch this plugin
  2. Use HTTP from @ionic-native/http (You can download files with it.)
sdkester commented 3 years ago

@nunohorta Like @elvisgraho I control the number of file transfers that are sent to the cordova plugin. My preferred library is the queue flow control in AsyncJS. This lets us send one or two file download requests at a time with a realtime queue waiting for additions and completions.