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

Consul Health indicator not showing in SpringBoot' actuator health endpoint

Open mbentar opened this issue 5 years ago • 6 comments

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 :

enter image description here

But when I test the same call with the parent application context instead, I get the following : AnnotationConfigApplicationContext

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.

mbentar avatar Aug 20 '20 09:08 mbentar

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?

plmaheu avatar Aug 22 '20 16:08 plmaheu

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.

mbentar avatar Aug 24 '20 08:08 mbentar

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.

plmaheu avatar Sep 01 '20 03:09 plmaheu

You should set debug=true in your properties and see the auto configuration report and see why ConsulAutoConfiguration.ConsulHealthConfig.consulHealthIndicator() is ignored.

spencergibb avatar Jan 27 '21 19:01 spencergibb

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.

spring-cloud-issues avatar Feb 03 '21 19:02 spring-cloud-issues

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).

M3hdi avatar Feb 08 '21 09:02 M3hdi

closing as it is resolved in supported versions

spencergibb avatar Mar 08 '23 22:03 spencergibb