We noticed one of our minimal webflux based services was leaking file descriptors every 30 seconds

...
java    23973  xx  539u     sock                0,8       0t0 277263 protocol: TCPv6
java    23973  xx  540u     sock                0,8       0t0 277327 protocol: TCPv6
java    23973  xx  541u     sock                0,8       0t0 277392 protocol: TCPv6
java    23973  xx  542u     sock                0,8       0t0 277454 protocol: TCPv6
java    23973  xx  543u     sock                0,8       0t0 277516 protocol: TCPv6
...

This didn't occur with our pure webmvc based services. We traced it down to the following sequence 1. Every 30 seconds, a HeartbeatEvent is created, triggering a refresh of the config service instance list through org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration.HeartbeatListener 2. This calls org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration#eurekaConfigServerInstanceProvider which in turn uses the reactive web client through a blocking interface (com.netflix.discovery.shared.transport.EurekaHttpClient#getApplications) 3. Within org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient#getApplicationsInternal occurs a call to .block() which leaks the connection

We worked around this by disabling the heartbeat listener.

@Configuration
@ConditionalOnBean(name = ["heartbeatListener"])
class EurekaHeartbeatFix {
    @Autowired
    private lateinit var context: ApplicationContext

    @Autowired
    private lateinit var heartbeatListener: SmartApplicationListener

    @PostConstruct
    fun removeEurekaHeartbeatListener() {
        val parent = context.parent?.getBean(
            AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
            ApplicationEventMulticaster::class.java
        )

        parent?.removeApplicationListenerBean("heartbeatListener")
        parent?.removeApplicationListener(heartbeatListener)
    }
}

Library Versions: spring-cloud-netflix-eureka-client:2.2.3.RELEASE spring-cloud-config-client:2.2.3.RELEASE OS: Linux

Comment From: spencergibb

Version 2.2.4.RELEASE make WebClient opt in so you shouldn't need that work around anymore.

@rstoyanchev does any of this sound familiar that calling exchange().block() on a WebClient call would leak a connection?

Comment From: rstoyanchev

It shouldn't but with exchange() you are responsible to handle all possible response types. From a quick look, I see handling for OK but what if there is a different response? I think the code could be re-written to use .retrieve() instead probably with .toEntity(Application.class).

I would also double check, is it a leak or is it using connections from the pool?