Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

DefaultEurekaClientHttpRequestFactorySupplier HttpClient is not closed #4062

Closed
Ive4 opened this issue Jan 12, 2022 · 6 comments
Closed

DefaultEurekaClientHttpRequestFactorySupplier HttpClient is not closed #4062

Ive4 opened this issue Jan 12, 2022 · 6 comments

Comments

@Ive4
Copy link

Ive4 commented Jan 12, 2022

Describe the bug
spring cloud 2021.0.0
Eureka Client has a bug, the bug is that every time the heartbeat and request Eureka Server will create a new HttpClient, but this new HttpClient will not be manually closed, only when the FullGC will be cleaned up, so it leads to the problem of too much TCP CLOSE_WAIT.

Sample
The solution is to provide a shared HttpClient, rather than re-creating a new one for each request.

@OlgaMaciaszek
Copy link
Collaborator

Hello, @Ive4 thanks for submitting this. I'm not sure what you mean. In the CloudEurekaClient that handles publishing the HeartbeatEvent, this method is called that should reuse an existing EurekaHttpClient. Could you please point me to the code you have in mind or provide a minimal, complete, verifiable example that reproduces the issue along with the steps to reproduce?

@Ive4
Copy link
Author

Ive4 commented Jan 21, 2022

Sorry, I didn't make it clear.
Eureka publishing HeartbeatEvent will invoke RedirectingEurekaHttpClient.execute.
EurekaClient will shutdown when an exception occurs on an http request, but not shutdown HttpClient

@OlgaMaciaszek
Copy link
Collaborator

Hello, @Ive4 if I understand correctly, the issue concerns the RedirectingEurekaHttpClient itself rather than its Spring integration provided by Spring Cloud? If so, please create an issue in the Eureka repo instead.

@spring-cloud-issues
Copy link

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-cloud-issues
Copy link

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

@BenEfrati
Copy link

BenEfrati commented May 2, 2022

Hi @OlgaMaciaszek ,
@Ive4 is right

EurekaClient will shutdown when an exception occurs on an http request, but not shutdown HttpClient

This bug is related to

In case of exception here:
https://github.com/Netflix/eureka/blob/ed0da19ca1c049c87e3dbf75b6015c1861d5c2d0/eureka-client/src/main/java/com/netflix/discovery/shared/transport/decorator/RedirectingEurekaHttpClient.java#L96
new HttpClient will be created without closing the existing one - this causes CLOSE_WAIT connections

I'll try to explain the issue, let me know if you still want complete mvce.
This supplier creates new CloseableHttpClient for every call to

public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClientHttpRequestFactorySupplier {

	@Override
	public ClientHttpRequestFactory get(SSLContext sslContext, @Nullable HostnameVerifier hostnameVerifier) {
		HttpClientBuilder httpClientBuilder = HttpClients.custom();
		if (sslContext != null) {
			httpClientBuilder = httpClientBuilder.setSSLContext(sslContext);
		}
		if (hostnameVerifier != null) {
			httpClientBuilder = httpClientBuilder.setSSLHostnameVerifier(hostnameVerifier);
		}
		CloseableHttpClient httpClient = httpClientBuilder.build();
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
		requestFactory.setHttpClient(httpClient);
		return requestFactory;
	}

}

so in case of shutdown, currentEurekaClient shutdown don't closes connections:

as @Ive4 said, only Full GC closes the opened connections.

possible solution will be trying to close the HttpClient:
shutdown could be

public void shutdown() {
        Optional.of(unwrapRequestFactoryIfNecessary(restTemplate.getRequestFactory()))
                .filter(HttpComponentsClientHttpRequestFactory.class::isInstance)
                .map(HttpComponentsClientHttpRequestFactory.class::cast)
                .ifPresent(requestFactory-> {
                    try {
                        requestFactory.destroy();
                    } catch (Exception e) {
                    }
                });
    }

unwrapRequestFactoryIfNecessary
https://github.com/spring-projects/spring-boot/blob/47516b50c39bd6ea924a1f6720ce6d4a71088651/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java#L746

spring-projects/spring-boot#31075

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants