I have a download task that work by first calling a REST API for which the server needs to generate a fairly large file which takes it several minutes to generate, as it is CPU and disk IO intensive. The client waits for the server to give a JSON response with the URL of the file it generated. The file download then starts after it gets the first result.
For the calls that generate a particularly large file, which causes the server to be very slow to respond, I am seeing duplicate requests that my code is not initiating.
Initially the someone who works on the server side told me about the duplicate requests. Then I set up a way to inspect network traffic. This was done by setting up a Mac connected to a wired network and enabling network sharing and using Proxyman to inspect the traffic from the iPhone to the API server. I see multiple instances of the same API request on the network layer but my code was never notified.
Code looks like this
@objc class OfflineMapDownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {
@objc func download(){
let config = URLSessionConfiguration.background(withIdentifier: "OfflineMapDownloadSession")
config.timeoutIntervalForRequest = 500
config.shouldUseExtendedBackgroundIdleMode = true
config.sessionSendsLaunchEvents = true
urlSession = URLSession(configuration: config, delegate: self, delegateQueue: nil)
getMapUrlsFromServer(bounds)
}
func getMapUrlsFromServer(){
var urlString = "http://www.fake.com/DoMakeMap.php"
if let url = URL(string: urlString) {
let request = NSMutableURLRequest(url: url)
//...Real code sets up a JSON body in to params...
request.httpBody = params.data(using: .utf8 )
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.timeoutInterval = 500
urlSession?.configuration.timeoutIntervalForRequest = 500
urlSession?.configuration.timeoutIntervalForResource = 500
request.httpShouldUsePipelining = true
let backgroundTask = urlSession?.downloadTask(with: request as URLRequest)
backgroundTask?.countOfBytesClientExpectsToSend = Int64(params.lengthOfBytes(using: .utf8))
backgroundTask?.countOfBytesClientExpectsToReceive = 1000
backgroundTask?.taskDescription = "Map Url Download"
backgroundTask?.resume()
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
if (downloadTask.taskDescription == "CTM1 Url Download") {
do {
let data = try Data(contentsOf: location, options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? Dictionary<String, AnyObject> {
if let ctm1Url = jsonResult["CTM1Url"] as? String {
if let filesize = jsonResult["filesize"] as? Int {
currentDownload?.ctm1Url = URL(string: ctm1Url)
currentDownload?.ctm1FileSize = Int32(filesize)
if (Int32(filesize) == 0) {
postDownloadFailed()
} else {
startCtm1FileDownload(ctm1Url,filesize)
}
}
}
}
} catch {
postDownloadFailed()
}
}
}
There is more to this download class as it will download the actual file once the first api call is done. Since the problem happens before that code would be executed, I did not include it in the sample code.
The log from Proxyman shows that the API call went out at (minutes:seconds) 46:06, 47:13, 48:21, 49:30, 50:44, 52:06, 53:45
It looks like the request gets repeated with intervals that are just over 1 minute.
There is an API field where I can put any value and it will be echoed back to me by the server. I put a timestamp there generated with CACurrentMediaTime() and log in Proxyman shows that indeed its the same API call so there is no way my code is getting called multiple times. It seems as though the iOS networking layer is re-issuing the http request because the server is taking a very long time to respond. This ends up causing problems on the server and the API fails.
Any help would be greatly appreciated.