Different timeouts in one URLSession - ios

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.

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.

Change socket timeout for grails 3 RestBuilder client post request

I have a grails 3 application using the grails.plugins.rest.client plugin to make calls to another API.The api performs some actions and responds in 40 to 50 seconds. The grails application timeout and returns a server error in 30 seconds. How can I change the timeout to wait for a response 60 seconds. My code is as follows:
import grails.plugins.rest.client.RestBuilder
import grails.plugins.rest.client.RestResponse
private RestBuilder rest = new RestBuilder()
RestResponse resp = rest.post(url) {
header 'Accept', "application/json"
json(data)
}
// more code
If you want to increase the socket timeout the grails rest client supports two options.
connectionTimeout
readTimeout
These options are to be set on the RestBuilder when it is instantiated. You cannot change this for request
types which is a shame.
To set them, you can use the below format. But bear in mind that it requires a change to the code and rebuilding the war file.
private RestBuilder rest = new RestBuilder(readTimeout: 180000, proxy: Proxy.NO_PROXY)
180000 = 180 seconds = 3 mins readTimeout
You can also set the connectionTimeout here, but most likely you will be limited by the connectiontimeOut property on the servlet container like Tomcat or CDN like cloudfront or cloudflare.
If you are also using tomcat, you may need to increase the async timeout like in the below example in directive. Hope this helps others looking to solve the same problem.
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
asyncTimeout="60000"
redirectPort="8443" />

URLRequest fails before timeout

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.

TimeoutInterval in Alamofire

If I set an 5 mins timeout interval for Alamofire request like below, it means an individual/overall API sync would take 5 mins?
sessionConfiguration.timeoutIntervalForRequest = 300
self.defaultManager = Alamofire.SessionManager(configuration: sessionConfiguration, serverTrustPolicyManager: policyManager)
No, it means that max time for timeout response is 300 seconds. If API finishes earlier you won't have to wait that much.
Regarding second question - it depends on your backend. For most cases 60 seconds is more then enough, however if you have any call that exceed it then you need to increase it. Note that it doesn't take parsing time into the consideration, just getting response from server. If you have large object that needs x minutes to parse but get it in 50 seconds it will be fine.
The main reason for timeout is because your server might never response and instead of letting your app hang, you can handle timeout error somehow.

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.

Resources