URLRequest fails before timeout - ios

I want to set different timeouts for different requests. My request routine looks like:
var request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalCacheData,
timeoutInterval: timeout)
// setting headers and body...
sessionTask = localURLSession.dataTask(with: request)
sessionTask?.resume()
where localURLSession is defined as public var:
public var localURLSession: Foundation.URLSession {
return Foundation.URLSession(configuration: localConfig, delegate: self, delegateQueue: nil)
}
public var localConfig: URLSessionConfiguration {
let res = URLSessionConfiguration.default
res.timeoutIntervalForRequest = Self.ordinaryRequestsTimeout // 20 seconds
return res
}
Then I have 2 problems:
When I make 2 simultaneous requests with 100% loss Network Link
Conditioner (first with 20 seconds timeout and second – with 40
seconds), both requests fails after 8 seconds. I don't understand
why.
When I make one request for the first time with 100% loss
Network Link Conditioner, it fails in timeout like expected, but
retrying this request fails in 1 second. I want to wait all the
timeout every time.

In all likelihood, for the 8-second failure, the DNS request is timing out, so you aren't connecting at all.
For the 1-second failure, the OS has probably concluded that the host is unreachable, and won't even try again until the network changes or it successfully makes at least one request to some host somewhere (negative DNS caching).
That said, without a packet trace, I can't be certain of either of those statements.

Related

Timeout interval not set for POST requests on iOS

I have a timeOutInterval set to 30 seconds on all my requests via this code:
class DefaultAlamofireSession: Alamofire.Session {
static let shared: DefaultAlamofireSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30
configuration.timeoutIntervalForResource = 30
return DefaultAlamofireSession(configuration: configuration)
}()
}
While testing, I noticed that only my GET requests get timed out at 30 seconds. My POST requests are still using the default interval which is 60 seconds.
Can anyone explain why and possibly tell me how I can make the POST requests also time out at 60 seconds?
Thanks a lot,
Paprika
URLSessionConfiguration.timeoutIntervalForRequest does not do what you think it does. From Apple's docs:
This property determines the request timeout interval for all tasks within sessions based on this configuration. The request timeout interval controls how long (in seconds) a task should wait for additional data to arrive before giving up. The timer associated with this value is reset whenever new data arrives. When the request timer reaches the specified interval without receiving any new data, it triggers a timeout.
So that property only controls the timeout between chunks of response Data. That's not typically what you want. Instead, you want to set the URLRequest.timeoutInterval directly, which does more of what you want.
If during a connection attempt the request remains idle for longer than the timeout interval, the request is considered to have timed out. The default timeout interval is 60 seconds.
As you can see, this timeout applies to the connection attempt, which is what most people think of as a request's timeout.
You can customize this value in Alamofire by applying a RequestAdapter to your custom Session. Or, you can use the requestModifier closure that available on the various request* methods.

Timeout when offline iOS (using waitsForConnectivity)

Whilst implementing several HTTP calls, I noticed some strange behaviour on the URLSession. As far as I know, URLSession data tasks used to immediately throw an error when the network connection was unavailable (error -1009 The Internet connection appears to be offline).
I'm now performing network requests too, and while executing a request in flight mode, the request runs for as long as the timeout, before failing. I tried creating a custom configuration that should prevent this, but this does not work. How can I re-enable or configure the behaviour where a request will immediately crash when there is no connection?
let url = URL(string: "https://www.google.com/")!
let config = URLSessionConfiguration.default
config.waitsForConnectivity = false
config.timeoutIntervalForRequest = 2
config.timeoutIntervalForResource = 0
URLSession(configuration: config).dataTask(with: url) { d, r, e in
print(d?.count, (r as? HTTPURLResponse)?.statusCode, e?.localizedDescription)
}.resume()
The configuration documentation appears to be inconsistent or incorrect.

Different timeouts in one URLSession

Is it possible to set different timeouts intervals per URLRequest using one URLSession?
I tried to set
urlRequest.timeoutInterval = 20 * 60
but it has been ignored by URLSession and request failed after default 60 sec with timeout error.
Only this setup change timeouts:
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 20 * 60 // 20 min
self.session = URLSession(configuration: configuration)
but 20 * 60 // 20 min is applied to all URLRequest in that session.
I want to allow some tasks to wait longer for response but rest of them should default failed after default 60 sec.
Is is possible? Or should I use more than one URLSession
PS. During research I found this bug:
https://bugs.swift.org/browse/SR-2680
You can have configure the timeout for each individual URL. It's just that you can't set a timeout that is bigger than the URLSession's configuration itself.
In some cases, the policies defined in this configuration may be
overridden by policies specified by an NSURLRequest object provided
for a task. Any policy specified on the request object is respected
unless the session’s policy is more restrictive. For example, if the
session configuration specifies that cellular networking should not be
allowed, the NSURLRequest object cannot request cellular networking.
Docs on URLSessionConfiguration
The default timeout is 60 seconds. You're setting to 1200 which is bigger. So it doesn't work. Increase your configuration and then you can configure each url's timeout differently.
Modifying a URLSession's properties after it has been assigned to a URLSession isn't supported, per Apple's documentation. You need to create the configuration separate and initialize a separate instance with it.

dataTaskWithRequest takes too long for a very specific string

I'm creating an IOS app using swift.
Recently, I've encountered a weird bug.
Im trying to check if a url is valid, therefore, I'm creating a request with the url and check for the response. I do this task with dataTaskWithRequest of NSUrlSession.
The weird bug is that if the URL is alibaba ,the response returns after a long time(more than 20 seconds sometimes).
Why does that happen?
As far as i concerned it happens only with this specific url.
Here is some code although its not necessary .
let request = NSMutableURLRequest(URL: validatedUrl)
request.HTTPMethod = "HEAD"
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request){ data, response, error in
// The response here returns after a very long time
let url = request.URL!.absoluteString
I would appreciate some help guys!
You're retrieving the contents of a URL over the Internet. The speed at which this happens is arbitrary. It depends on the speed of the DNS server that looks up the hostname, the speed of the web server that responds to the request, the speed of the user's Internet connection, and the speed of every network in between.
You can safely assume that it will either succeed or time out within three minutes. Twenty seconds isn't even slightly unusual over a cellular network.
You should probably rethink what you're doing with this URL and why you're doing it, or at least try to figure out a way to avoid keeping the user waiting while you fetch the URL.

Alamofire slowing down on each request

I am using Alamofire to do a basic requests to an API endpoint. I noticed that the more often I do these tests, the longer the Alamofire request seems to take.
I can reproduce this behaviour with the code sample below. This does a bunch of requests and prints the duration of the request to the console. The last request is about .5 seconds slower than the first one. The amount of slow down seems to be related to the amount of JSON the API returns (our API returns much more data and the slow down is much more significant)
Am I hitting some kind of caching mechanism here?
let testURL = "https://httpbin.org/get"
for var i = 0; i < 100; i++ {
let startDate = NSDate()
Alamofire.request(.GET, testURL)
.responseJSON { response in
print("Duration of request: \(NSDate().timeIntervalSinceDate(startDate))")
}
}
The problem here is not Alamofire, but how you are measuring the latency. You are queueing 100 requests, so the time it takes for each is very small. But since they are queued up, when the last request runs, will depend on the majority of previous requests finishing.
You should use the request timeline object to obtain the latency, with
request.timeline.totalDuration, for example.

Resources