httpclient exception "org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection"
JavaExceptionHttpclientJava Problem Overview
I am trying to send request to my server, with following code. it failed at 3rd request, always.
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
public class HttpClientTest {
private HttpClient client;
public HttpClientTest() {
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15000);
params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 15000);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf-8");
HttpProtocolParams.setUseExpectContinue(params, true);
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
cm.setMaxTotal(100);
client = new DefaultHttpClient(cm, params);
while (true) {
HttpPost mPost = new HttpPost("http://myip/myservice");
JSONObject json = new JSONObject();
try {
json.put("serialNumber", "abcd");
} catch (JSONException e1) {
e1.printStackTrace();
}
StringEntity s = null;
try {
s = new StringEntity(json.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
mPost.setEntity(s);
JSONObject response = null;
System.out.println("HttpClientTest ---> send post");
HttpResponse mHttpResponse;
try {
mHttpResponse = client.execute(mPost);
System.out.println("HttpClientTest ---> get response");
if(mHttpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
HttpEntity entity = mHttpResponse.getEntity();
ContentType contentType = ContentType.getOrDefault(entity);
Charset charset = contentType.getCharset();
response = new JSONObject(new JSONTokener(new InputStreamReader(entity.getContent(), charset)));
System.out.println("HttpClientTest ---> get result:" + response.toString());
} else {
mPost.abort();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
HttpClientTest t = new HttpClientTest();
}
}
the exception as following:
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute.getEntryBlocking(ConnPoolByRoute.java:417)
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1.getPoolEntry(ConnPoolByRoute.java:300)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1.getConnection(ThreadSafeClientConnManager.java:224)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:401)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.i360r.client.takeaway.network.HttpClientTest.<init>(HttpClientTest.java:68)
at com.i360r.client.takeaway.network.HttpClientTest.main(HttpClientTest.java:88)
Java Solutions
Solution 1 - Java
I had the same problem and I found the fix.
This timeout is because of a connection leak. In my case, I'm using httpDelete
method and not consuming the response. Instead, I'm checking the status of the response.
The fix is, the response entity needs to be consumed. In order to ensure the proper release of system resources, one must close the content stream associated with the entity.
So I used EntityUtils.consumeQuietly(response.getEntity());
which ensures that the entity content is fully consumed and the content stream, if exists, is closed.
Solution 2 - Java
I have fixed it! add mPost.releaseConnection()
in finally
blocks.
try {
} catch (Exception e) {
} finally {
mPost.releaseConnection();
}
DO update package org.apache.httpcomponents
to 4.2.1
Solution 3 - Java
Just put the line where you are getting your response inside try-with-resources and use CloseableHttpResponse instead of HttpResponse like this:
try(final CloseableHttpResponse mHttpResponse = client.execute(mPost);)
{
System.out.println("HttpClientTest ---> get response");
....remainder code
The mHttpResponse object will be auto consumed and closed for you
Hope this helps!
Solution 4 - Java
Use a CloseableHttpClient
instead of HttpClient
. You'll get a CloseableHttpResponse
instead of a HttpResponse
which support close()
. So, when you are done with the response, just close it, no need to close the connection.
CloseableHttpResponse response = closableHttpClient.execute(httpPost, context);
...do what you need to do with it:
response.close();
Solution 5 - Java
This can also happen if you're using ApacheHttpClient
with DropWizard 0.6.2, which behind the scenes creates an MultiThreadedHttpConnectionManager
with a default configuration - and that default configuration only allowed 2 concurrent http connections at a time more info here.
So with this configuration, if your server is getting swamped and making requests to the same host all the time, you'll have max 2 connections allowed running at a time!
Solution 6 - Java
We faced the same issue, and we were limited because the connection from pool has initial value of DefaultMaxPerRoute as 2. Ours was an API which would fire different calls with same URI but, different body. Once we set it explicitly to higher value like this
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(40);
cm.setDefaultMaxPerRoute(20);
we were able to resolve it.
Solution 7 - Java
We were hitting this error when writing and reading parquets via spark.
The exact error was:
com.amazonaws.SdkClientException: Unable to execute HTTP request: Timeout waiting for connection from pool
We finally figured out that this was related to the upgrade of Hadoop to version 3.1.3
Seems that in this new version the Hadoop, the property name been changed from:
fs.s3a.connection.maximum
to:
spark.hadoop.fs.s3a.connection.maximum
Renaming the property in our spark configuration, set us back on track.
Solution 8 - Java
I hit the same error. It turns out that I needed to close the response.
CloseableHttpResponse response = null;
try {
response = ##some code
} catch(Exception e) {
if (response != null) {
response.close();
}
}
Solution 9 - Java
As Rama said, this could be a sign of a connection leak.
releaseConnection()
could help resolve this issue but you might need to find out the root cause.
Also, this could happen because there's no available connection you can lease which could happen when you don't have timeout
config for the HttpClient
. In this case, releaseConnection()
wouldn't help.
Solution 10 - Java
In my case the bufferedReader that was consuming the entity content stream was not being closed. Closing it resolved the error.