I'm using spring integration with an http-outbound-gateway using the HttpComponentsClientHttpRequestFactory. I'm having the following exception NoHttpResponseException.
2019-08-13 16:09:51,839 http-bio-8443-exec-439 ERROR LoggingHandler:184 - org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://my-service.com/my-service]; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:409)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://my-service.com/my-service": my-service.com:443 failed to respond; nested exception is org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:633)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:516)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:382)
... 213 more
Caused by: org.apache.http.NoHttpResponseException: my-service.com:443 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:261)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:165)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:272)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
... 216 more
Searching around I found this link that stale connections where the problem, so I wanted to evict the them as it's said in the docs
One of the major shortcomings of the classic blocking I/O model is that the network socket can react to I/O events only when blocked in an I/O operation. When a connection is released back to the manager, it can be kept alive however it is unable to monitor the status of the socket and react to any I/O events. If the connection gets closed on the server side, the client side connection is unable to detect the change in the connection state (and react appropriately by closing the socket on its end).
HttpClient tries to mitigate the problem by testing whether the connection is 'stale', that is no longer valid because it was closed on the server side, prior to using the connection for executing an HTTP request. The stale connection check is not 100% reliable. The only feasible solution that does not involve a one thread per socket model for idle connections is a dedicated monitor thread used to evict connections that are considered expired due to a long period of inactivity. The monitor thread can periodically call ClientConnectionManager#closeExpiredConnections() method to close all expired connections and evict closed connections from the pool. It can also optionally call ClientConnectionManager#closeIdleConnections() method to close all connections that have been idle over a given period of time.
<int-http:outbound-gateway id="httpOutboundGateway" request-channel="requestServiceHttpChannel"
reply-channel="responseServiceHttpChannel" url-expression="headers.serviceUrl" http-method="POST"
expected-response-type="java.lang.String" charset="UTF-8" request-factory="httpOutboundRequestFactoryBean"
message-converters="messageConverterList" header-mapper="headerMapperBean"/>
<bean id="httpOutboundRequestFactoryBean"
class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="readTimeout" value="${http.service.timeout.readResponse}"/>
<property name="connectTimeout" value="${http.service.timeout.connection}"/>
</bean>
Unfortunatelly, Spring abstractions offers only to modify timeouts, but I cannot change the pool configuration or access the pool manager to do it as the http client docs says.
One option is to extend the HttpComponentsClientHttpRequestFactory and add methods to access the HttpClientConnectionManager from a cron job to clean the stale connections, but maybe there is a better option you know
Is there a spring integration abstraction I can use to clean stale connections on http-outboung-gateway using the HTTPClient from apache?