4

It looks like Spring's WebServiceTemplate is ignoring setting for connection timeout. That, or I am misunderstanding connection timeout.

Here is my configuration:

@Bean
public SoapTemplate soapTemplate(Jaxb2Marshaller marshaller, WebServiceMessageSender webServiceMessageSender ) {

    SoapTemplate template = new SoapTemplate();
    template.setDefaultUri("some_url");
    template.setMarshaller(marshaller);
    template.setUnmarshaller(marshaller);
    template.setMessageSender(webServiceMessageSender);
    return template;
}

@Bean
public WebServiceMessageSender webServiceMessageSender() {

    HttpComponentsMessageSender sender =  new HttpComponentsMessageSender();

    sender.setReadTimeout(5*1000);
    sender.setConnectionTimeout(5*1000);

    return sender;

}

Soap template extends WebServiceGateway and has some specific logging, custom exception features.

When I start target application which should receive SOAP messages generated by WebServiceTemplate, read timeout works as intended. If the server does not respond within specified time, an exception is thrown.

My understanding was that connection timeout should happen if the TCP 3-Way Handshake doesn't happen within specified time. This is not the case however, as timeout always happens after ~ 2 second, regardless of my configuration.

Is this a valid test, or connection timeout should be tested with congested server that is online but cannot accept new connections ? Which timeout is my client experiencing then and can it be controlled ?

John
  • 5,189
  • 2
  • 38
  • 62

1 Answers1

3

This does not explain the problem but the HttpComponentsMessageSender's default constructor uses the deprecated org.apache.http.impl.client.DefaultHttpClient. Try using the org.apache.http.client.HttpClient:

@Bean
public HttpComponentsMessageSender webServiceMessageSender() {

  final HttpClient httpClient = buildHttpClient(5*1000, 5*1000, 2, true);
  final HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient);
  return messageSender;
}

@SuppressWarnings("resource")
private static HttpClient buildHttpClient(final int connectionTimeout, final int socketTimeout, final int retryCount, final boolean trustAll) {

    // timeout config
    final RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectionTimeout).setSocketTimeout(socketTimeout).build();

    // trust all (if selected)
    SSLConnectionSocketFactory sslSocketFactory = null;
    if (trustAll) {
        try {
            final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustAllStrategy()).build();
            sslSocketFactory = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            throw new RuntimeException("could not initialize SSL context, reason: " + e.getMessage(), e);
        }
    }

    // socket factory
    final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", trustAll ? sslSocketFactory : SSLConnectionSocketFactory.getSocketFactory()).build();

    // retry handler
    final HttpRequestRetryHandler retryHandler = new SimpleRetryHandler(retryCount);

    // build client
    final HttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig)
        .setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryRegistry)).setRetryHandler(retryHandler)
        .addInterceptorFirst(new RemoveSoapHeadersInterceptor()).build();

    return httpClient;
}

Update: The custom buildHttpClient method was used in a project where we used SSL connections. If you don't need the SSL part, try to remove it step-by-step.

Sebastian S.
  • 1,545
  • 6
  • 24
  • 41