spring-cloud-consul icon indicating copy to clipboard operation
spring-cloud-consul copied to clipboard

dependency cycle when Use my own ConsulServiceRegistry with spring-boot-starter-actuator

Open c1emon opened this issue 2 years ago • 3 comments

When consul set with discovery.heartbeat.enabled=true and spring-boot-starter-actuator's health endpoint enabled.

At same time, spring-boot-starter-data-mongodb also added. Use my own ConsulServiceRegistry.

Startup and comes with dependency cycle for consul's TtlScheduler! Here is my example with logs, spring_consul_err.

c1emon avatar Oct 11 '23 08:10 c1emon

I'm having the same issue, but without overriding anything from consul, just having spring-cloud-starter-consul-discovery, spring-boot-starter-actuator and spring-boot-starter-data-mongodb-reactive on the same classpath and enabling the spring.cloud.consul.discovery.heartbeat.enabled=true. Here's a reproduction project

ghimisradu avatar Nov 07 '23 09:11 ghimisradu

in heartbeat, set use-actuator-health to false

        heartbeat:
            use-actuator-health: false
            enabled: true

You can check the ConsulHeartbeatAutoConfiguration to find out the issue

@ConditionalOnProperty(value = "spring.cloud.consul.discovery.heartbeat.use-actuator-health", havingValue = "true",
			matchIfMissing = true)
	static class ActuatorBasedApplicationStatusProviderConfig

gc-garcol avatar Dec 17 '23 08:12 gc-garcol

Startup and comes with dependency cycle for consul's TtlScheduler! Here is my example with logs, spring_consul_err.

Copying the cycle here for clarity

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   stationController defined in file [/Users/clemon/Downloads/demo/build/classes/java/main/com/example/demo/station/StationController.class]
┌─────┐
|  mongoTemplate defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDatabaseFactoryDependentConfiguration.class]
↑     ↓
|  mappingMongoConverter defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDatabaseFactoryDependentConfiguration.class]
↑     ↓
|  mongoMappingContext defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDataConfiguration.class]
↑     ↓
|  consulAutoServiceRegistrationListener defined in class path resource [org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.class]
↑     ↓
|  consulAutoServiceRegistration defined in class path resource [org/springframework/cloud/consul/serviceregistry/ConsulAutoServiceRegistrationAutoConfiguration.class]
↑     ↓
|  commonConsulServiceRegistry defined in class path resource [com/example/demo/consul/CommonConsulAutoConfiguration.class]
↑     ↓
|  ttlScheduler defined in class path resource [org/springframework/cloud/consul/support/ConsulHeartbeatAutoConfiguration.class]
↑     ↓
|  actuatorHealthStatusProvider defined in class path resource [org/springframework/cloud/consul/support/ConsulHeartbeatAutoConfiguration$ActuatorBasedApplicationStatusProviderConfig.class]
↑     ↓
|  healthEndpoint defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]
↑     ↓
|  healthContributorRegistry defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]
↑     ↓
|  mongoHealthContributor defined in class path resource [org/springframework/boot/actuate/autoconfigure/data/mongo/MongoHealthContributorAutoConfiguration.class]
└─────┘

Here is my analysis:

  • mongoMappingContext is a InitializingBean
  • During initialization it produces MappingContextEvents (which is subtype of ApplicationEvent)
  • consulAutoServiceRegistrationListener is a SmartApplicationListener
  • SmartApplicationListener extends ApplicationListener<ApplicationEvent>
  • So it is necessary to create consulAutoServiceRegistrationListener to handle events from mongoMappingContext, thus cycle appears

WebServerInitializedEvent is the only event type that consulAutoServiceRegistrationListener can process, so It should be enough to explicitly declare it in bean definiton to fix this issue. Either by changing implements SmartApplicationListener to implements ApplicationListener<WebServerInitializedEvent> or annotating onApplicationEvent method with @EventListener(WebServerInitializedEvent.class).

Unfortunately I don't have time to test this hypothesis, but I would be glad if someone could do it and submit a PR if everything works fine.

chillb0nes avatar Jan 11 '24 16:01 chillb0nes