Steps to Reproduce
- Download rest-client-issue.zip. It uses Spring Boot 4.0.0-RC2 and Spring Framework Web 7.0.0-RC3.
- Run the tests in
RestClientIssueApplicationTests
Expected Outcome
All tests should pass.
Actual Outcome
Last test is blocked and is waiting for 3 minutes until it reaches the time-out which is set for Apache HTTP Client 5. If you just execute this one single test it works out fine.
Analysis
This behaviour seems to occur only with Apache HTTP Client 5. After 5 tests/HTTP connections to the same server (route) the client doesn't get a response anymore.
2025-11-08T23:05:48.258+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000001 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 0 of 5; total allocated: 0 of 25]
2025-11-08T23:05:48.259+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000001 endpoint leased [route: {}->[http://localhost:56211]][total available: 0; route allocated: 1 of 5; total allocated: 1 of 25]
2025-11-08T23:05:48.324+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000002 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 1 of 5; total allocated: 1 of 25]
2025-11-08T23:05:48.324+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000002 endpoint leased [route: {}->[http://localhost:56211]][total available: 0; route allocated: 2 of 5; total allocated: 2 of 25]
2025-11-08T23:05:48.351+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000003 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 2 of 5; total allocated: 2 of 25]
2025-11-08T23:05:48.351+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000003 endpoint leased [route: {}->[http://localhost:56211]][total available: 0; route allocated: 3 of 5; total allocated: 3 of 25]
2025-11-08T23:05:48.375+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000004 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 3 of 5; total allocated: 3 of 25]
2025-11-08T23:05:48.375+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000004 endpoint leased [route: {}->[http://localhost:56211]][total available: 0; route allocated: 4 of 5; total allocated: 4 of 25]
2025-11-08T23:05:48.381+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000005 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 4 of 5; total allocated: 4 of 25]
2025-11-08T23:05:48.381+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000005 endpoint leased [route: {}->[http://localhost:56211]][total available: 0; route allocated: 5 of 5; total allocated: 5 of 25]
2025-11-08T23:05:48.387+01:00 DEBUG h.i.i.PoolingHttpClientConnectionManager : ex-0000000006 endpoint lease request (3 MINUTES) [route: {}->[http://localhost:56211]][total available: 0; route allocated: 5 of 5; total allocated: 5 of 25]
After all routes are allocated the client is blocked.
[ERROR] Tests run: 6, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 181.4 s <<< FAILURE! -- in at.aztec.spring.RestClientIssueApplicationTests
[ERROR] at.aztec.spring.RestClientIssueApplicationTests.shouldAllowInfoEndpoint -- Time elapsed: 180.0 s <<< ERROR!
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost: 56211/actuator/info": Timeout deadline: 180000 MILLISECONDS, actual: 180004 MILLISECONDS
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createResourceAccessException(DefaultRestClient.java:763)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:615)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeForRequiredValue(DefaultRestClient.java:572)
at org.springframework.test.web.servlet.client.DefaultRestTestClient$DefaultRequestBodyUriSpec.exchange(DefaultRestTestClient.java:289)
at at.aztec.spring.RestClientIssueApplicationTests.shouldAllowInfoEndpoint(RestClientIssueApplicationTests.java:42)
Caused by: org.apache.hc.core5.http.ConnectionRequestTimeoutException: Timeout deadline: 180000 MILLISECONDS, actual: 180004 MILLISECONDS
at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.acquireEndpoint(InternalExecRuntime.java:122)
at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:127)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:195)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:151)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:112)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:110)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:87)
at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.apache.hc.client5.http.classic.HttpClient.executeOpen(HttpClient.java:183)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:99)
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:80)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeWithRequest(AbstractBufferingClientHttpRequest.java:89)
at org.springframework.http.client.InterceptingClientHttpRequest$EndOfChainRequestExecution.execute(InterceptingClientHttpRequest.java:102)
at org.springframework.test.web.servlet.client.DefaultRestTestClient$WiretapInterceptor.intercept(DefaultRestTestClient.java:531)
at org.springframework.http.client.ClientHttpRequestInterceptor.lambda$apply$0(ClientHttpRequestInterceptor.java:89)
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:73)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:50)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:80)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:609)
... 3 more
If you set the parameter close of the method exchangeForRequiredValue in org.springframework.test.web.servlet.client.DefaultRestTestClient.DefaultRequestBodyUriSpec.exchange() to true instead of false (currently hardcoded) this issue doesn't occur.
But I doubt this would be the correct solution since HTTP connections should be reused from the connection pool.