2

A backend API I need to connect to takes about 3-4 minutes to return a response. The iOS client seems to timeout at exactly 60 seconds (which is the default), and I can't figure out how to extend that time out.

I have tried to set the timeoutInterval for the NSURLRequest to a large number, and set the Connection: Keep-Alive header, but I have no luck. Here is the code I am using, omitting some API details:

NSURL *url = [NSURL URLWithString:@"myAPI"];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"POST"];

NSString *postString = @"key1=val1&key2=val2...";
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];

request.timeoutInterval = 600.0f;

[request setValue:@"Keep-Alive" forHTTPHeaderField:@"Connection"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
     NSLog(@"data = %@", data);
}];

No data is returned and all response header fields are empty, even though the backend API is still processing the request.

I heard I might need to set something called a "socketTimout" interval so the socket knows to keep the connection open longer, but I do not know where to set that.

Erik Villegas
  • 954
  • 13
  • 29

3 Answers3

7

Rather than trying to extend the timeout, it would be a better idea to modify your server architecture a bit. Have the server kick back a 200 OK as soon as it gets all the data, then have the processing done in a background queue. Create another API call that you can use to retrieve the data and have the iOS app check that at regular intervals to see if the data has been processed. Alternatively, use a push notification to the let the user/phone know when the data is done processing.

If you happen to be using Ruby on Rails it's extremely easy to set long-running processes to happen on a worker thread. Take a look the delayed_job Ruby gem.

If for some reason you cannot modify how the server operates, try making sure the API you are using doesn't have a timeout set itself. I can't think of a reason iOS would be ignoring the the timeoutInterval you're setting, unless that property is read only. Try using this init method instead:

- initWithURL:cachePolicy:timeoutInterval:
Andrew Theis
  • 933
  • 7
  • 15
1

Have you tried using the NSURLConnection delegate methods instead of sendAsynchronousRequest?

By using:

NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];

You can monitor the delegate method didReceiveData and append the incoming data to an instance of NSMutableData:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.data appendData:data];
}

That way, at least you'll know you're receiving data and you can even present your users with a progress bar or something.

dalton_c
  • 6,876
  • 1
  • 33
  • 42
  • I can try that, however there is no data being sent meanwhile. It takes long not because it is downloading a file, but because the server is doing heavy processing. When it finishes it returns a simple JSON response, which the app does not receive due to timing out too early. – Erik Villegas May 09 '13 at 20:35
  • Oh wow. That's an interesting phenomenon. Andrew's answer is a good suggestion. Rather than force the iPhone to wait on the server's processing, establish multiple API calls to initiate the process, and to query it's completion status. Another suggestions would be to setup a cron job on your server that performs this process at regular intervals. That way, when the iPhone is ready to receive the data, the server can just return the most recent result of the process, rather than perform the process at that time. – dalton_c May 09 '13 at 21:57
0

Erik, check the answer on this post:

NSURLConnection timeout?

Essentially you use this method on NSURLRequest

requestWithURL:cachePolicy:timeoutInterval:

Community
  • 1
  • 1
Aaron
  • 7,055
  • 2
  • 38
  • 53