Httpclient 4.5 taking double time for closing the http connection - java

I have given the connectiontimeout 5000 milliseconds(5 second) but actually it takes 10127 milliseconds(10.127 second)
if connectiontimeout=10000 milliseconds(10 second) then it is taking 20032 milliseconds(20 second) for connection time out
below is the code which i tried.
public static void getTest()
{
long start=0;
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://testing url");
RequestConfig config=null;
config = RequestConfig.custom()
.setConnectTimeout(5000)
.setConnectionRequestTimeout(5000)
.setSocketTimeout(5000)
.build();
httpGet.setConfig(config);
start = System.currentTimeMillis();
httpClient.execute(httpGet);
} catch (Exception e) {
long end=System.currentTimeMillis();
System.out.println("total time in Milliseconds:="+(end-start));
}
}

The reason is unsuccessful HTTP POST request will be automatically re-sent to the server. Unsuccessful post means, in this case, the server did not send a valid HTTP response or an IOException occurred and HTTP PostRetry default value is true in JVM. There are servral ways to prevent from silent HttpRetry please refer below-mentioned table.
That's the main reason for doubled the exact timeout.

Related

HTTPClient hung or slow in multi-threaded environment

I am using following version of httpclient api to call the rest webservice.
httpcore4.4.9
httpclient 4.5.9
I am using the ExecutorService to execute the task where it is calling my following methods to get the data from rest API. ExecutorService execute about 30+ rest call in one transaction and i observed that, httpclient HUNG or SLOW for few of the rest call and it hit the performance issue. Can you please check if below i am using httpclient correct way ?
String output = null;
CloseableHttpClient httpClient = getHttpClients();
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
output = EntityUtils.toString(entity);
EntityUtils.consume(response.getEntity());
} catch (Exception e) {
log.error("error during call to REST API " + httpGet.getURI() + " ", e);
} finally {
httpClient.close();
httpGet.releaseConnection();
httpGet.abort();
}
return output;
}
private CloseableHttpClient getHttpClients() {
long startTime = System.currentTimeMillis();
long endTime = 0;
int timeout = 12000;
RequestConfig.Builder requestBuilder = RequestConfig.custom();
requestBuilder.setConnectTimeout(timeout);
requestBuilder.setConnectionRequestTimeout(timeout);
SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(timeout).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
builder.disableContentCompression();
builder.setDefaultSocketConfig(socketConfig);
CloseableHttpClient httpClient = builder
.build();
endTime = System.currentTimeMillis();
log.debug("Total time took to build client = " + (endTime - startTime));
return httpClient;
} ```
As per my experience, this problem is occurring because of EntityUtils.consume(response.getEntity()) .
You could find what it actually does here.
Try removing and running your code to match the speed and decide if you want it or not.
Below is the code used by me:
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpGet request = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity());
} catch (Exception ex) {
log.error(ex.toString());
}
Try to adjust MaxTotal and MaxPerRoute variable in PoolingHttpClientConnectionManager class.
connectionManager.setMaxTotal(maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

How to apply proper error handling of TimeOut for httpclient

In my Xpages application I am calling an external service to collect data.
Users are complaining that they sometimes get a timeout error message:
Connect to customerbank.acme.se:20543 [customerbank.acme.se/127.17.27.172] failed: Connection timed out: connect
I assumed the timeout would result in an IOException but apparently not. How can I catch this error?
Below is part of my code. The logic of handling the response I have left out.
private CloseableHttpClient httpclient;
try{
HttpClientBuilder cb = HttpClientBuilder.create();
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(30 * 1000)
.setConnectTimeout(30 * 1000)
.setConnectionRequestTimeout(30 * 1000)
.build();
cb.setDefaultRequestConfig(requestConfig);
httpclient = cb.build();
HttpPost httpPost = new HttpPost(urlFromConfiguration);
httpPost.setHeader("Content-Type", "application/json");
HttpEntity entity;
entity = new ByteArrayEntity(JSONobj.toString().getBytes("UTF-8"));
httpPost.setEntity(entity);
CloseableHttpResponse response = httpclient.execute(httpPost);
if (200 == response.getStatusLine().getStatusCode()){//response received
//perform some logic with the response...
}
} catch (IOException e) {
OpenLogUtil.logError(e);
FacesContext.getCurrentInstance().addMessage(null, new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, "some IO exception occurred", ""));
} catch (Exception e) {
OpenLogUtil.logError(e);
FacesContext.getCurrentInstance().addMessage(null, new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, "some general error has occured" , ""));
}
I think this Baeldung page can help you:
"Note that the connection timeout will result in an
org.apache.http.conn.ConnectTimeoutException being thrown, while
socket timeout will result in a java.net.SocketTimeoutException."
Apache Http client that you are using is a great utility. But it could be a bit heavy and cumbersome for a relatively simple task that you are running. There is a much simpler Http client provided in MgntUtils Open source library (written by me). It may be not as comprehensive as Apache one, but is much simpler in use. It does throw IOException upon connection or time-out error. In your case it could be an alternative to use. Take a look at Javadoc. Library itself provided as Maven artifacts and on Git (including source code and Javadoc). All in all your code may look like this:
private static void testHttpClient() {
HttpClient client = new HttpClient();
client.setContentType("application/json");
String content = null;
try {
content = client.sendHttpRequest("http://yourUrl.com", HttpMethod.POST, JSONobj.toString());
//content holds the response. Do your logic here
} catch (IOException e) {
//Error Handling is here
content = TextUtils.getStacktrace(e, false);
}
}

How to force Apache HttpClient / HttpConnection to absolutely close tcp connection?

I use lot of http connection with Apache HttpClient (org.apache.httpcomponents 4.3.6) to test servers and I cannot force connections to close, even when I schedule HttpConnectionManager to httpClient.getConnectionManager().shutdown(); after 10 seconds in another thread.
httpClient.close() also doesn't help.
Connections can last for minutes or even hours.
I have tried custom SocketConfig and this also not helps:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(false)
.setSoLinger(5)
.setSoReuseAddress(true)
.setSoTimeout(5000)
.setTcpNoDelay(true).build();
The way I am fetching the content:
HttpUriRequest request = new HttpGet(url);
HttpResponse response = httpClient.execute(request);
try (InputStream in = response.getEntity().getContent()) {
String result = IOUtils.toString(in, StandardCharsets.UTF_8);
httpClient.close();
return result;
}
The way I am building HTTP Client:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(false)
.setSoLinger(configuration.getInt("proxy.list.socket.so.linger"))
.setSoReuseAddress(true)
.setSoTimeout(configuration.getInt("proxy.list.socket.so.timeout"))
.setTcpNoDelay(true).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.disableAutomaticRetries();
builder.disableContentCompression();
builder.disableCookieManagement();
builder.disableRedirectHandling();
builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
builder.setDefaultSocketConfig(socketConfig);
One of my prototypes of doing shutdown:
shutdownExecutor.schedule(() -> {
httpClient.getConnectionManager().closeExpiredConnections();
httpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.SECONDS);
httpClient.getConnectionManager().shutdown();
httpClient.notifyAll();
try {
httpClient.close();
} catch (IOException ex) {
}
}, configuration.getInt("proxy.test.forced.timeout.seconds"), TimeUnit.SECONDS);
String content = HttpContentFetcher.getAndCloseClient(url, httpClient);
RequestConfig has helped. Now it looks like all the connections are discarded in specified limits.
RequestConfig config= RequestConfig.custom()
.setCircularRedirectsAllowed(false)
.setConnectionRequestTimeout(4000)
.setConnectTimeout(4000)
.setMaxRedirects(0)
.setRedirectsEnabled(false)
.setSocketTimeout(4000)
.setStaleConnectionCheckEnabled(true).build();
request.setConfig(config);

How to send HttpPost every 5 secs

In a Java, I want to send HttpPost every 5 secs without waiting for the response. How can I do that?
I use the following code:
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
StringEntity params = new StringEntity(json.toString() + "\n");
post.addHeader("content-type", "application/json");
post.setEntity(params);
httpClient.execute(post);
Thread.sleep(5000);
httpClient.execute(post);
but it does not work.
Even though I lose the previous connection and set up a new connection to send the second, the second execute function is always blocked.
Your question leaves a bunch of questions, but the basic point of it can be achieved by:
while(true){ //process executes infinitely. Replace with your own condition
Thread.sleep(5000); // wait five seconds
httpClient.execute(post); //execute your request
}
I tried your code and I got the exception :
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
This exception is already logged in HttpClient 4.0.1 - how to release connection?
I was able to release the connection by consuming the response with the following code:
public void sendMultipleRequests() throws ClientProtocolException, IOException, InterruptedException {
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.google.com");
HttpResponse response = httpClient.execute(post);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
Thread.sleep(5000);
response = httpClient.execute(post);
entity = response.getEntity();
EntityUtils.consume(entity);
}
Using DefaultHttpClient is synchronous which means that program is blocked waiting for the response. Instead of that you could use async-http-client library to perform asynchronous requests (you can download jar files from search.maven.org if you're not familiar with Maven). Sample code may look like:
import com.ning.http.client.*; //imports
try {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
while(true) {
asyncHttpClient
.preparePost("http://your.url/")
.addParameter("postVariableName", "postVariableValue")
.execute(); // just execute request and ignore response
System.out.println("Request sent");
Thread.sleep(5000);
}
} catch (Exception e) {
System.out.println("oops..." + e);
}

Apache HttpComponents HttpClient timeout

How do I set the connection timeout in httpcomponents httpclient? I have found the documentation at: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html but it is not clear how these parameters are actually set.
Also, an explanation of the difference between SO_TIMEOUT and CONNECTION_TIMEOUT would be helpful.
In version 4.3 of Apache Http Client the configuration was refactored (again). The new way looks like this:
RequestConfig.Builder requestBuilder = RequestConfig.custom();
requestBuilder.setConnectTimeout(timeout);
requestBuilder.setConnectionRequestTimeout(timeout);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
HttpClient client = builder.build();
In HttpClient 4.3 version you can use below example.. let say for 5 seconds
int timeout = 5;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpGet request = new HttpGet("http://localhost:8080/service"); // GET Request
response = client.execute(request);
The answer from #jontro is correct, but it's always nice to have a code snippet on how to do this. There are two ways to do this:
Version 1: Set a 10 second timeout for each of these parameters:
HttpClient httpclient = new DefaultHttpClient();
// this one causes a timeout if a connection is established but there is
// no response within 10 seconds
httpclient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 10 * 1000);
// this one causes a timeout if no connection is established within 10 seconds
httpclient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10 * 1000);
// now do the execute:
HttpGet httpget = new HttpGet(URL);
HttpResponse response = httpclient.execute(httpget);
Version 2: Also set a 10 second timeout for each of these parameters:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 10 * 1000);
HttpConnectionParams.setSoTimeout(params, 10 * 1000);
HttpClient httpclient = new DefaultHttpClient(params);
HttpGet httpget = new HttpGet(URL);
HttpResponse response = httpclient.execute(httpget);
In section 2.5 you see an example of how to set the CONNECTION_TIMEOUT parameter.
CONNECTION_TIMEOUT is the time waiting for the initial connection and SO_TIMEOUT is the timeout that you wait for when reading a packet after the connection is established.
I set a hard timeout for the entire request to workaround the java.net.SocketInputStream.socketRead0 problem.
private static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newSingleThreadScheduledExecutor()
HttpGet request = new HttpGet("http://www.example.com")
final Runnable delayedTask = new Runnable() {
#Override
public void run() {
request.abort()
}
}
SCHEDULED_EXECUTOR.schedule(delayedTask, 100000, TimeUnit.MILLISECONDS)

Categories