Search code examples
httpclient

Httpclient throws Timeout waiting for connection from pool exception


Now am working on an exception for our uploading image service, the scenario below:

We have a web page, user from all over the world can upload their images to our server, the image normally keep about 3MB. Now we held a promotion, so the images number uploading to our server is extremely huge, which, however caused the server throws the exception as "org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool".

We use apache httpclient as the core uploading middleware, its version is 4.5.*, we correctly handled the response by using the method mentioned in this article. The code like below:

 if (returnType != StorageHttpResponse.class && response != null) {
        EntityUtils.consumeQuietly(response.getEntity());
        httpRequest.abort();
    }

Also, the max connection pool for the service is 128 and the max connection time out is 50000 ms. We upload the images by using stream mode, not directly upload the image file.

So here, I correctly handled the response entity by consuming it in finally code block, but I still can't stop the service throw connection pool timeout exception.

Any other stuffs that I need to add to my service? Do I really using redis to make a queue to user's uploading requests and post handling?

Whole code here:

 public <T> T excute(Request request, Class<T> returnType) {
    Preconditions.checkState(!isShutDown, "JSSHttpClient is destory!");
    HttpRequestBase httpRequest = new HttpRequestBuild(this.credential).build(request);
    HttpResponse response = null;
    try {
        response = this.client.execute(httpRequest);
        if (errorHandler.hasError(request, response)) {
            int statusCode = response.getStatusLine().getStatusCode();
            log.warn("Unexpected response," + request + " http code [" + statusCode + "]");
            errorHandler.handleError(response);
        }
        if (returnType != null && returnType != StorageHttpResponse.class) {
            return JsonMessageConverter.read(returnType, response);
        }
        if (returnType == StorageHttpResponse.class) {
            return (T) new StorageHttpResponse(response);
        }
    } catch (IOException e) {
        Throwables.propagate(e);
    } finally {
        if (returnType != StorageHttpResponse.class && response != null) {
            EntityUtils.consumeQuietly(response.getEntity());
            httpRequest.abort();
        }
    }
    return null;
}

Solution

  • you can set the parameters in either properties or yml file like below.

    http:
      pool:
        size: 100
        sockettimeout: 20000
        defaultMaxPerRoute: 200
      maxPerRoutes:
        -
          scheme: http
          host: localhost
          port: 8080
          maxPerRoute: 100
        -
          scheme: https
          host: {{URL}}
          port: -1
          maxPerRoute: 200