httpclient exception "org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection"

Viewed 80419

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)
10 Answers

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();

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.

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.

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();
  }
}

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.

In my case the bufferedReader that was consuming the entity content stream was not being closed. Closing it resolved the error.

Related