In order to add my custom health indicator I injected HealthContributorRegistry and then registered my contributor. I did this because I saw that HealthContributorRegistry was autoconfigured (required for HealthEndpoint)

Later on I've found that my custom contributor was not present - I realized that ReactiveHealthContributorRegistry was used instead.

I wonder if it would be feasible to update ReactiveHealthContributorRegistry when HealthContributorRegistry is being updated.

Current setup seems to be unintuitive - there are no clear guidelines what should be configured and how reactive parts interact with traditional ones.

Comment From: nosan

Hi @kkocel,

I injected HealthContributorRegistry and then registered my contributor.

This is quite an unusual way to register your own HealthIndicator. The best practice, in my opinion, is to register HealthIndicator as a @Bean or mark it with @Component annotation.

@Configuration(proxyBeanMethods = false)
public class HealthConfiguration {

    @Bean
    public HealthContributor myHealth(){
        return ...
    }
}

Here is more information: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#writing-custom-healthindicators

Comment From: kkocel

@nosan it's totally valid to register HealthIndicator at runtime, see: https://github.com/spring-projects/spring-boot/pull/4965 In my use case I need to create them dynamically and I use registry that was designed for that.

The problem is that those two types of registries do not share their HealthIndicator.

Comment From: wilkinsona

Thanks for the report.

I wonder if it would be feasible to update ReactiveHealthContributorRegistry when HealthContributorRegistry is being updated.

I don't think we can do that. The adaptation of a blocking health contributor into something that's suitable for reactive use is done outside of the registries by a call to org.springframework.boot.actuate.health.ReactiveHealthContributor.adapt(HealthContributor). That's all handled automatically for health contributors that are exposed as beans.

There may be something that we can do to simplify things for the dynamic case. Failing that, we can improve the documentation to explain what needs to be done and why. Right now, I'm not 100% sure that I understand exactly what you were trying to do, @kkocel. I'm guessing your using the reactive stack but registering a blocking contributor.

To remove any doubt, could you please put together a small sample that illustrates what you're doing and share it with us as a zip attached to this issue or in a separate GitHub repository?

Comment From: kkocel

@wilkinsona - it is exactly my case - I use reactive stack but I've registered to blocking contributor. I've got confused because blocking one (HealthContributorRegistry) was getting autowired. reactivehealthindicator.zip

Comment From: snicoll

@kkocel thank you for the sample and the feedback.

// I need to explicitly call ReactiveHealthContributorRegistry instead of HealthContributorRegistry

That quote in your sample looks like a problem but I fail to see why that is. If you're using the reactive stack, then you should use the reactive contract. Taking Spring Data as an example, you use the Reactive repositories variant, not the imperative ones.

The documentation also has an explicit note about this use case

In a reactive application, The ReactiveHealthContributorRegistry can be used to register and unregister health indicators at runtime.

I guess the only thing that's missing is an improvement of the doc for adapting an health indicator if you want to register a blocking one at runtime. @kkocel have I missed anything?

Comment From: kkocel

@snicoll there were two confusing parts: 1. why HealthContributorRegistry gets autoconfigured when I use reactive stack 2. when I register HealthContributor during runtime in one registry does this imply registering same/adapted contributor in another one

After figuring out that populating one registry does not affect another I just switched to reactive counterparts - and that was fairly easy.

When I saw that HealthEndpointConfiguration has some adapting logic between reactive and non-reactive worlds I've assumed that such adapting mechanism can be also in place during runtime. It turned out that such assumption was wrong.

I would consider two options - either clearly stating that registering in runtime won't affect another registry, or provide such link in AutoConfiguredHealthContributorRegistry.registerContributor. I don't know if latter would be feasible though...

Comment From: snicoll

@kkocel thanks but that doesn't really answer my question about the doc.

I would consider two options - either clearly stating that registering in runtime won't affect another registry,

It clearly states already (I think) that a reactive application should use the ReactiveHealthContributorRegistry. I agree that if you have to register a blocking indicator at runtime, the doc can be improved and we'll do that using this issue.

About your first point, detecting a reactive application is not a clear cut (making assumptions about a web application can be dangerous and lead to false positive). I've flagged the issue to get some more feedback from the team.

Comment From: kkocel

For current implementation docs are accurate and imho shouldn't be changed.

I wonder about feature parity though - should runtime registration behave in same way as bean one?

So do you suggest that there is no clear way to find out if reactive web app is being used?

If there is then I would consider adding feature parity.

If there isn't then I would consider splitting reactive and non-reactive worlds apart.