spring-cloud-netflix: EurekaClient shutdown causing BeanCreationNotAllowedException which prevents unregistration of the client from the registry (RefreshScope)
BeanCreationNotAllowedException
is thrown during application context shutdown by the DiscoveryClient
.
This is issue has already been reported since long in different scenarios and different (apparent) causes. There have been many attempts at solving the issue so far, but unfortunately, although each attempt solved one cause, there are still cases where the exception is thrown.
A short summary first before a more detailed description below:
- the problem occurs during shutdown of the application after the eureka client has successfully registered with the registry
- the problem does NOT occur if the SpringCloud RefreshScope feature is disabled via
spring.cloud.refresh.enabled=false
. RefreshScope is the root cause in this scenario. - it can be easily reproduced with Boot
2.0.4
or1.5.14
(ie Spring CloudEdgware.SR4
orFinchley.SR1
) - the exception prevents the client from being unregistered from the registry during shutdon
The problem can be easily reproduced with a simple Spring Initilizr bootstrap project with only the Eureka Discovery
dependency selected. This is reproductible with Boot 2.0.4
or 1.5.14
(ie Spring Cloud Edgware.SR4
or Finchley.SR1
).
You need a running Eureka server so the sample client can be successfully registered. Start the application with the standard configuration (nothing special needed here) and make sure it is registered with the Eureka registry. Then stop the application properly so the shutdown sequence is executed (Ctrl-C should do it). You should see the following log lines during the shutdown:
2018-09-03 13:50:26.443 INFO 9494 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2018-09-03 13:50:26.443 INFO 9494 --- [on(2)-127.0.0.1] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7a362b6b: startup date [Mon Sep 03 13:49:45 CEST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@5c30a9b0
2018-09-03 13:50:26.444 INFO 9494 --- [on(2)-127.0.0.1] o.s.c.n.e.s.EurekaServiceRegistry : Unregistering application unknown with eureka with status DOWN
2018-09-03 13:50:26.444 WARN 9494 --- [on(2)-127.0.0.1] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1535975426444, current=DOWN, previous=UP]
2018-09-03 13:50:26.444 INFO 9494 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_UNKNOWN/macfury.lan: registering service...
2018-09-03 13:50:26.445 INFO 9494 --- [on(2)-127.0.0.1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
2018-09-03 13:50:26.446 INFO 9494 --- [on(2)-127.0.0.1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2018-09-03 13:50:26.446 INFO 9494 --- [on(2)-127.0.0.1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans
2018-09-03 13:50:26.448 INFO 9494 --- [on(2)-127.0.0.1] com.netflix.discovery.DiscoveryClient : Shutting down DiscoveryClient ...
2018-09-03 13:50:26.450 WARN 9494 --- [on(2)-127.0.0.1] .s.c.a.CommonAnnotationBeanPostProcessor : Invocation of destroy method failed on bean with name 'scopedTarget.eurekaClient': org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'eurekaInstanceConfigBean': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
2018-09-03 13:50:26.455 INFO 9494 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_UNKNOWN/macfury.lan - registration status: 204
2018-09-03 13:50:26.505 INFO 9494 --- [on(2)-127.0.0.1] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
As you can see in the last few lines, a BeanCreationNotAllowedException
exception is thrown when destroying the bean scopedTarget.eurekaClient
. The remaining part of the message gives us some hints about what’s going on:
Error creating bean with name ‘eurekaInstanceConfigBean’: Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
The DiscoveryClient#shutdown()
method starts with the following statements:
(1) public synchronized void shutdown() {
(2) if (isShutdown.compareAndSet(false, true)) {
(3) logger.info("Shutting down DiscoveryClient ...");
(4)
(5) if (statusChangeListener != null && applicationInfoManager != null) {
(6) applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId());
(7) }
The exception is thrown when the execution hits line (6)
.
You should remember both the DiscoveryClient
and ApplicationInfoManager
are RefreshScope
beans (unless the Refresh feature is disabled with spring.cloud.refresh.enabled=false
, it is enabled by default). Consequence is the applicationInfoManager
is a refresh-scope proxy whose target must be resolved when the unregisterStatusChangeListener
is invoked - this is done via a getBean(..)
call on the application context.
The shutdown
method is invoked by the application context during its shutdown procedure. At this point the underlying BeanFactory is in a closing state and actively refuses any getBean(...)
call made by other components, throwing BeanCreationNotAllowedException
at any attempt.
Let’s recap:
- DiscoveryClient.shutdown() is invoked during the application context shutdown/close process
- DiscoveryClient needs to unregister from the ApplicationInfoManager
- applicationInfoManager is refresh-scoped, its target must be resolved for every method invocation
- the resolution fails with a BeanCreationNotAllowedException because the BeanFactory is in closing state.
At the end, we do actually request a bean from a BeanFactory in a destroy method implementation!, which is, as per the exception message, not allowed.
The problem does NOT appear if the refresh feature is disabled with spring.cloud.refresh.enabled=false
.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 19 (18 by maintainers)
Commits related to this issue
- Additional test cases to illustrate some of the failure cases discovered while troubleshooting https://github.com/spring-cloud/spring-cloud-netflix/issues/3174 — committed to brenuart/spring-cloud-commons by brenuart 6 years ago
- By not using the proxy in the EurekaClient we avoid the problem of trying to fetch the bean during shutdown. Fixes #3174 — committed to ryanjbaxter/spring-cloud-netflix by ryanjbaxter 6 years ago
- Do Not Use AIM Proxy In EurekaClient (#3240) * By not using the proxy in the EurekaClient we avoid the problem of trying to fetch the bean during shutdown. Fixes #3174 — committed to spring-cloud/spring-cloud-netflix by ryanjbaxter 6 years ago
ping @dsyer @ryanjbaxter @spencergibb any news on this ?