If you’re using Spring WebFlux and encountering shutdown warnings like this:
WARN 24696 --- [on(2)-127.0.0.1] o.a.c.loader.WebappClassLoaderBase :
The web application [ROOT] started thread [reactor-http-epoll-1] but failed to stop it.
This is very likely to create a memory leak.
You have a Netty thread shutdown issue, which can lead to memory leaks. This guide will help you resolve it permanently.
Why This Happens
Spring WebFlux relies on Netty for non-blocking I/O. When running your application:
- Netty creates event loop threads (
reactor-http-epoll-*
) to manage requests. - If these threads aren’t explicitly closed during shutdown, they linger, causing memory leaks.
Common Causes:
- Improper use of multiple
WebClient
instances. - Missing Netty resource cleanup during application shutdown.
Step-by-Step Fix
1. Remove Spring MVC Conflicts
Ensure spring-boot-starter-web
is not included in pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Remove spring-boot-starter-web -->
2. Use a Singleton WebClient
Instead of instantiating multiple WebClient
objects, define them as Spring beans:
WebClient Configuration:
@Configuration
public class WebClientConfig {
@Bean
public WebClient pokemonWebClient() {
return WebClient.builder()
.baseUrl("https://pokeapi.co")
.build();
}
@Bean
public WebClient catWebClient() {
return WebClient.builder()
.baseUrl("https://cataas.com")
.build();
}
}
Service Implementation:
@Service
public class WebClientService {
private final WebClient pokemonWebClient;
private final WebClient catWebClient;
public WebClientService(
@Qualifier("pokemonWebClient") WebClient pokemonWebClient,
@Qualifier("catWebClient") WebClient catWebClient
) {
this.pokemonWebClient = pokemonWebClient;
this.catWebClient = catWebClient;
}
public Mono<String> callApis() {
return Mono.zip(callPokemonApi(), callCatApi())
.map(tuple -> tuple.getT1() + " *** " + tuple.getT2());
}
private Mono<String> callPokemonApi() {
return pokemonWebClient.get()
.uri("/api/v2/pokemon/salamence")
.retrieve()
.bodyToMono(String.class);
}
private Mono<String> callCatApi() {
return catWebClient.get()
.uri("/api/cats")
.retrieve()
.bodyToMono(String.class);
}
}
3. Gracefully Shut Down Netty Threads
Explicitly close Netty’s HttpClient
during shutdown:
Netty Shutdown Configuration:
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;
import reactor.netty.http.client.HttpClient;
@Configuration
public class NettyShutdownConfig {
private final HttpClient httpClient;
public NettyShutdownConfig(
@Qualifier("pokemonWebClientHttpClient") HttpClient pokemonClient,
@Qualifier("catWebClientHttpClient") HttpClient catClient
) {
this.httpClient = HttpClient.merge(pokemonClient, catClient);
}
@PreDestroy
public void shutdown() {
httpClient.dispose();
}
}
Modify WebClientConfig
to Expose HttpClient
:
@Bean
public HttpClient pokemonWebClientHttpClient() {
return HttpClient.create();
}
@Bean
public WebClient pokemonWebClient(HttpClient httpClient) {
return WebClient.builder()
.baseUrl("https://pokeapi.co")
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
4. Verify Dependencies
Ensure your dependencies are up-to-date:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.9</version>
</parent>
Why This Works
- Singleton WebClient: Prevents excessive resource usage and improves efficiency.
- Explicit Netty Shutdown: Ensures event loop threads are properly closed, avoiding leaks.
- Dependency Cleanup: Eliminates conflicts between MVC and WebFlux.
Key Takeaways
✅ Use a singleton WebClient to avoid redundant resource allocation.
✅ Shut down Netty’s HttpClient
explicitly with @PreDestroy
.
✅ Remove unnecessary dependencies that may cause conflicts.
By following these best practices, you can eliminate thread-related warnings and ensure a smooth shutdown for your Spring WebFlux application.
Meta Description: Learn how to fix Spring WebFlux thread leaks with a step-by-step guide. Discover how to properly shut down Netty threads, prevent memory leaks, and optimize WebClient usage.
Tags: Spring WebFlux, Netty thread leak, WebClient shutdown, memory leak fix, reactive programming, Spring Boot, Netty HttpClient, async threads
Keywords: Spring WebFlux stop threads, Netty graceful shutdown, WebClient memory leak, fix reactor-http-epoll warning, Spring Boot WebFlux Netty, dispose HttpClient, Spring reactive thread management