Reputation: 446
I have two Spring Boot Services A and B. Also an external service C. That's the request path:
Web Browser <-> service A <-> Service B <-> External Service C
The external service is returning a resource which goes back to frontend. For communication between A, B and C I'm using Rest Template. Everything goes fine when entering the Web App but as soon as I'm running BDD tests which are running in parallel (9 threads) I'm getting NoHttpResponseException in service B when calling External Service C.
org.apache.http.NoHttpResponseException Service_C failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
Here is my Rest Template configuration:
@Bean
public RestTemplate restTemplateExternal() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpComponentsClientHttpRequestFactory requestFactory = getRequestFactoryWithDisabledSSLValidation();
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
private HttpComponentsClientHttpRequestFactory getRequestFactoryWithDisabledSSLValidation() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return requestFactory;
}
I've already tried to call connectionManager.setValidateAfterInactivity(0);
but it doesn't help.
Let me add that all the request from service B to external service C are to the same endpoint. Only parameter (x) is changing:/resource?param={x}
To be honest I'm not 100% sure if HttpClient is gonna be created with each request to service (RestTemplate bean is Singleton) or is that only one instance per service?
Maybe i need to 'setDefaultMaxPerRoute' in Connection Manager? If yes then how do i distinguish what is the proper number? I'd really appreciate a brief description of how to properly configure RestTemplate in such case.
Upvotes: 8
Views: 19902
Reputation: 1142
If you want to see the retry in the logs, you can use the retry solution like this:
private void addRetryHandler( HttpClientBuilder httpClientBuilder ) {
logger.debug("adding retry handler to httpClient");
httpClientBuilder.setRetryHandler(( exception, executionCount, context ) -> {
if (executionCount > 3) {
logger.debug("Maximum http request tries reached for client http pool ");
return false;
}
if (exception instanceof org.apache.http.NoHttpResponseException) {
logger.debug("No response from server on {} call, got NoHttpResponseException", executionCount);
return true;
}
return false;
});
}
Upvotes: 0
Reputation: 985
The problem may be because the response contains header connections=close
. Thus a connection is closed but the next request tries to reuse the existing connection (which is closed) and get the error.
setRetryHandler
will always fail at first connection reuse but then start a new connection on the second retry and will succeed then.
You can disalow to reuse connections with following line:
httpClient.setReuseStrategy(new NoConnectionReuseStrategy());
Upvotes: 4
Reputation: 446
Looks like that's a similar issue here: get NoHttpResponseException for load testing
Tried with clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));
and it made the trick. I'd still appreciate if someone could explain the problem more deeply.
Upvotes: 5
Reputation: 171
U can try to enable more additional logging for searching hidden exceptios from server. It seems like that the server breaks connection.
Upvotes: -2