spring-cloud-consul
spring-cloud-consul copied to clipboard
Consul Health indicator not showing in SpringBoot' actuator health endpoint
I have a SpringBoot based web application that exposes a consul health indicator bean.
The bean is correctly created and initialized by springboot's autoconfiguration, yet, the indicator is not showing in the actuator health endpoint despite the fact that the associated configuration property "management.health.consul.enabled" is set to true:
{
"status": "UP",
"components": {
"Kafka": {...},
"SchemaRegistry": {...},
"discoveryComposite": {...},
"diskSpace": {...},
"ping": {...},
"refreshScope": {...}
}
}
Upon further inspection, I found the bellow snippet that is responsible for fetching all the available indicators (HealthEndpointConfiguration.java) :
@Bean
@ConditionalOnMissingBean
HealthContributorRegistry healthContributorRegistry(ApplicationContext applicationContext,
HealthEndpointGroups groups) {
Map<String, HealthContributor> healthContributors = new LinkedHashMap<>(
applicationContext.getBeansOfType(HealthContributor.class));
if (ClassUtils.isPresent("reactor.core.publisher.Flux", applicationContext.getClassLoader())) {
healthContributors.putAll(new AdaptedReactiveHealthContributors(applicationContext).get());
}
return new AutoConfiguredHealthContributorRegistry(healthContributors, groups.getNames());
}
Setting a break point there, I see that indeed the ConsulHealthIndicator bean is not listed in the output of the applicationContext.getBeansOfType(HealthContributor.class) call as shows bellow :
But when I test the same call with the parent application context instead, I get the following :

Can someone please shed some light on why this particular bean is present in the root context but not in the child context ?
Is there a way to force it's initialisation in the child context so that it will get correctly registered in the health endpoint ?
I've attached a sample project allowing the reproduction of the issue. I've also included a sample of consul configuration that is used by the app (you can import it via consul import command). Running the example above and going to the health endpoint (localhost:8080/monitoring/health) you will clearly see that the consul component is missing from the list.
Thank you in advance.
Usually the class extending SpringBootServletInitializer is the one that's annotated with @SpringBootApplication. Can you try that and see if you still have the same issue?
I moved the SpringBootServletInitializer as suggested but the issue is still there :
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class ConsulIntegrationSampleApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ConsulIntegrationSampleApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ConsulIntegrationSampleApplication.class);
}
}
On the other hand, a workaround to get it working was to supply my own my own HealthContributorRegistry where I take into account the parent context when performing the HealthContributor beans lookup :
@Bean
HealthContributorRegistry healthContributorRegistry(ApplicationContext applicationContext, HealthEndpointGroups groups) {
Map<String, HealthContributor> healthContributors = new LinkedHashMap<>(applicationContext.getBeansOfType(HealthContributor.class));
ApplicationContext parent = applicationContext.getParent();
while (parent != null) {
healthContributors.putAll(parent.getBeansOfType(HealthContributor.class));
parent = parent.getParent();
}
return new DefaultHealthContributorRegistry(healthContributors);
}
This is clearly suboptimal, Ideally the consul indicator should be working out of the box like the rest of the health contributors.
I noticed the health check wasn't showing up in my system either. After digging I figured out the cause: the health check auto config is part of the Consul auto config so it gets created in the bootstrap context. That's why you see it in the parent context, that;s the bootstrap context in Spring Cloud Config.
I'll make a PR when I have a bit of time.
You should set debug=true in your properties and see the auto configuration report and see why ConsulAutoConfiguration.ConsulHealthConfig.consulHealthIndicator() is ignored.
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.
ConsulAutoConfiguration.ConsulHealthConfig#consulHealthIndicator matched:
- @ConditionalOnMissingBean (types: org.springframework.cloud.consul.ConsulHealthIndicator; SearchStrategy: all) did not find any beans (OnBeanCondition)
- @ConditionalOnEnabledHealthIndicator management.health.defaults.enabled is considered true (OnEnabledHealthIndicatorCondition)
As you see above, the consul auto-configuration is matched and the health indicator is created. The problem is that the health indicator bean is registered into the root spring context and is therefore missed when the call to applicationContext.getBeansOfType(HealthContributor.class) is made.
That said, the above issue (reproducible on SpringBoot 2.3 / Hoxton.SR8 version), seems to be resolved with SpringBoot 2.4 in combination of the latest spring cloud release (2020.0.0).
closing as it is resolved in supported versions
