Using Apache HttpClient how to set the TIMEOUT on a request and response
Asked Answered
H

2

41

I need to set time out for the Http Request we make to a service (not a web service). We are using Apache HTTP Client. I have added these 2 lines of code to set the time out on request and response to the service.

HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);

1) Currently I have set 10 seconds as the timeout since I see the response coming from the service almost instantaneously. Should I increase or decrease the timing?

2) What will happen when response is takes more than 10 seconds? Will it throw exception and what exception will it be? Is there any thing else I need to add to set the time out in the below code.

public HashMap<String, Object> getJSONData(String url) throw Exception{
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpParams params = httpClient.getParams();
    HttpConnectionParams.setConnectionTimeout(params, 10000);
    HttpConnectionParams.setSoTimeout(params, 10000);
    HttpHost proxy = new HttpHost(getProxy(), getProxyPort());
    ConnRouteParams.setDefaultProxy(params, proxy);
    URI uri;
    InputStream data = null;
    try {
        uri = new URI(url);
        HttpGet method = new HttpGet(uri);
        HttpResponse response = httpClient.execute(method);
        data = response.getEntity().getContent();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    Reader r = new InputStreamReader(data);
    HashMap<String, Object> jsonObj = (HashMap<String, Object>) GenericJSONUtil.fromJson(r);
    return jsonObj;
}
Harrow answered 26/3, 2012 at 14:15 Comment(0)
L
37

The exceptions you'll see will be ConnectTimeoutException and SocketTimeoutException. The actual timeout values you use should be the maximum time your application is willing to wait. One important note about the read timeout is that it corresponds to the timeout on a socket read. So it's not the time allowed for the full response to arrive, but rather the time given to a single socket read. So if there are 4 socket reads, each taking 9 seconds, your total read time is 9 * 4 = 36 seconds.

If you want to specify a total time for the response to arrive (including connect and total read time), you can wrap the call in a thread and use a thread timeout for that. For example, I usually do something like this:

Future<T> future = null;
future = pool.submit(new Callable<T>() {
    public T call() {
        return executeImpl(url);
    }   
}); 

try {
    return future.get(10, TimeUnit.SECONDS);
}   
catch (InterruptedException e) {
    log.warn("task interrupted", name);
}   
catch (ExecutionException e) {
    log.error(name + " execution exception", e); 
}   
catch (TimeoutException e) {
    log.debug("future timed out", name);
}

Some assumptions made in the code above are: 1) this is in a function with a url parameter, 2) it's in a class with a name variable, 3) log is a log4j instance, and 4) pool is a some thread pool executor. Note that even if you use a thread timeout, you should also specify a connect and socket timeout on the HttpClient, so that slow requests don't eat up the resources in the thread pool. Also note that I use a thread pool because typically I use this in a web service so the thread pool is shared across a bunch of tomcat threads. You're environment may be different, and you may prefer to simply spawn a new thread for each call.

Also, I've usually see the timeouts set via member functions of the params, like this:

params.setConnectionTimeout(10000);
params.setSoTimeout(10000);

But perhaps your syntax works as well (not sure).

Likker answered 26/3, 2012 at 14:21 Comment(5)
What is that i need to set/add if i have to allow the Full Response time arriveHarrow
Can you please explain what do you mean by 4 socket read? If they are 4 socket read then there will be 4 different request associated with that read.Harrow
no, the response can come in chunks. If you look at any low level socket code you'll see that read() happens in a while loop, and the return value of read() is the number of bytes read. There is no requirement that the entire response come in a single socket read. I'll update my answer to include more detail.Likker
The synax for setting the time out works. i have tested it and works fine.Harrow
Don't you mean: return future.get(10, TimeUnit.SECONDS)? Or you genuinely want to wait ten thousand seconds?Gigantic
O
77

I am guessing many people come here because of the title and because the HttpConnectionParams API is deprecated.

Using a recent version of Apache HTTP Client, you can set these timeouts using the request params:

HttpPost request = new HttpPost(url);

RequestConfig requestConfig = RequestConfig.custom()
  .setSocketTimeout(TIMEOUT_MILLIS)
  .setConnectTimeout(TIMEOUT_MILLIS)
  .setConnectionRequestTimeout(TIMEOUT_MILLIS)
  .build();

request.setConfig(requestConfig);

Alternatively, you can also set this when you create your HTTP Client, using the builder API for the HTTP client, but you'll also need to build a custom connection manager with a custom socket config.

The configuration example file is an excellent resource to find out about how to configure Apache HTTP Client.

Ollayos answered 1/7, 2015 at 11:19 Comment(1)
Link is broken above. I think this is the correct (even if non-authoritative) link github.com/apache/httpcomponents-client/blob/master/httpclient5/…Flaxman
L
37

The exceptions you'll see will be ConnectTimeoutException and SocketTimeoutException. The actual timeout values you use should be the maximum time your application is willing to wait. One important note about the read timeout is that it corresponds to the timeout on a socket read. So it's not the time allowed for the full response to arrive, but rather the time given to a single socket read. So if there are 4 socket reads, each taking 9 seconds, your total read time is 9 * 4 = 36 seconds.

If you want to specify a total time for the response to arrive (including connect and total read time), you can wrap the call in a thread and use a thread timeout for that. For example, I usually do something like this:

Future<T> future = null;
future = pool.submit(new Callable<T>() {
    public T call() {
        return executeImpl(url);
    }   
}); 

try {
    return future.get(10, TimeUnit.SECONDS);
}   
catch (InterruptedException e) {
    log.warn("task interrupted", name);
}   
catch (ExecutionException e) {
    log.error(name + " execution exception", e); 
}   
catch (TimeoutException e) {
    log.debug("future timed out", name);
}

Some assumptions made in the code above are: 1) this is in a function with a url parameter, 2) it's in a class with a name variable, 3) log is a log4j instance, and 4) pool is a some thread pool executor. Note that even if you use a thread timeout, you should also specify a connect and socket timeout on the HttpClient, so that slow requests don't eat up the resources in the thread pool. Also note that I use a thread pool because typically I use this in a web service so the thread pool is shared across a bunch of tomcat threads. You're environment may be different, and you may prefer to simply spawn a new thread for each call.

Also, I've usually see the timeouts set via member functions of the params, like this:

params.setConnectionTimeout(10000);
params.setSoTimeout(10000);

But perhaps your syntax works as well (not sure).

Likker answered 26/3, 2012 at 14:21 Comment(5)
What is that i need to set/add if i have to allow the Full Response time arriveHarrow
Can you please explain what do you mean by 4 socket read? If they are 4 socket read then there will be 4 different request associated with that read.Harrow
no, the response can come in chunks. If you look at any low level socket code you'll see that read() happens in a while loop, and the return value of read() is the number of bytes read. There is no requirement that the entire response come in a single socket read. I'll update my answer to include more detail.Likker
The synax for setting the time out works. i have tested it and works fine.Harrow
Don't you mean: return future.get(10, TimeUnit.SECONDS)? Or you genuinely want to wait ten thousand seconds?Gigantic

© 2022 - 2024 — McMap. All rights reserved.