0

Short Version: Is it possible to configure a custom retry handler when using the ApacheConnectorProvider + PoolingHttpClientConnectionManager? If so, how?

Long Version: I'm using Jersey 2.25.1 and I've recently switched from using the default HTTP connection mechanism to the Apache PoolingHttpClientConnectionManager to improve the scaling ability of my automated test framework.

It is generally working, but as I scale, I get the occasional 'connect timeout'. I believe that the Apache HTTPClient has the ability to accept a custom retry handler, but I don't know how to configure a custom handler with Jersey. I can't find any examples in my many search attempts.

Something similar was asked 2 years ago Here but has no answers.

Here is my initialization code for the Jersey client:

    SSLContext ctx = initSSLTrustFactory();

    Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.getSocketFactory())
            .register("https", new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE))
            .build();

    ClientConfig cfg = new ClientConfig();

    PoolingHttpClientConnectionManager connMan = new PoolingHttpClientConnectionManager(registry);
    connMan.setMaxTotal(200);
    connMan.setDefaultMaxPerRoute(50);

    if (timeout != -1) {
        SocketConfig sc = SocketConfig.custom()
                .setSoTimeout(timeout)
                .setSoReuseAddress(true)
                .setTcpNoDelay(true)
                .setSoReuseAddress(true)
                .build();
        connMan.setDefaultSocketConfig(sc);
        cfg.property(ApacheClientProperties.REQUEST_CONFIG, RequestConfig
                .custom()
                .setConnectTimeout(timeout)
                .setConnectionRequestTimeout(timeout)
                .setSocketTimeout(timeout)
                .build()
        );
    }
    cfg.property(ApacheClientProperties.CONNECTION_MANAGER, connMan);

    ApacheConnectorProvider acp = new ApacheConnectorProvider();
    cfg.connectorProvider(acp);

    ClientBuilder builder = JerseyClientBuilder.newBuilder();
    client = builder
            .hostnameVerifier((String hostname, SSLSession session) -> true)
            .withConfig(cfg)
            .register(JacksonFeature.class)
            .register(MultiPartWriter.class)
            .build(); 

There is an example HERE that shows one way to set it on the actual Apache HTTPClient, but I don't see a way to do the equivalent in Jersey but I'm still trying to understand how to customize Jersey.

I would have thought it done by doing something in the ClientConfig instance similar to:

cfg.property(ApacheClientProperties.RETRY_HANDLER, new HttpRequestRetryHandler() {

    public boolean retryRequest(
            IOException exception,
            int executionCount,
            HttpContext context) {
         ...
    }
  }
);

But a retry handler client property setting does not exist.

Thanks for any pointers!

Community
  • 1
  • 1
Jeff Vincent
  • 433
  • 5
  • 10

2 Answers2

0

The support for RetryHandlers has been introduced in version 2.26. See ApacheClientProperties.RETRY_HANDLER here.

agabor
  • 662
  • 6
  • 7
0

I know this question is quite old, but in v 3.x of Apache HttpClient, you would be able to set your retry handler on a per-request level (PostMethod, now HttpPost), however it now appears you set this up when you create your HttpClient using the new 4.x builder pattern. Here's a code snippet setting up a client with a pooling connection manager and retry handler, hopefully this helps someone else having to migrate from v3 to v4.

public class HttpClientFactory {
  private static final int MAX_TOTAL_CONNECTIONS = 60;
  public static final int REMOTE_SEARCH_TIMEOUT_DEFAULT = 180000;

  private int connectionTimeout = REMOTE_SEARCH_TIMEOUT_DEFAULT;
  private int maxTotalConnections = MAX_TOTAL_CONNECTIONS;
  private final SomeCustomRetryHandler somecustomretryhandler = new SomeCustomRetryHandler();

  public HttpClient createHttpClient() {
    RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(3000)
            .setConnectionRequestTimeout(3000)
            .setSocketTimeout(3000)
            .build();

    return HttpClients.custom()
            .setConnectionManager(createPoolingHttpConnectionManager())
            .setDefaultRequestConfig(config)
            .setRetryHandler(somecustomretryhandler)
            .build();
  }

  private PoolingHttpClientConnectionManager createPoolingHttpConnectionManager() {
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    cm.setDefaultMaxPerRoute(getMaxTotalConnections(6);
    cm.setMaxTotal(6);
    return cm;
  }
}
Louis Moore
  • 607
  • 6
  • 6