Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Add hints for HealthContributors #1184

Closed
wants to merge 1 commit into from

Conversation

olivierboudet
Copy link
Contributor

Add hints for all HealthIndicator subclasses to fix #1183

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 24, 2021
@sdeleuze
Copy link
Contributor

@bclozel @snicoll Do you think this is something we could be able to infer?

@snicoll
Copy link
Contributor

snicoll commented Oct 25, 2021

Yes.

@olivierboudet thanks for the PR! Are you interested if I guide you to repurpose this PR with the AOT engine instead?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Oct 25, 2021
@olivierboudet
Copy link
Contributor Author

@snicoll yes sure.
In fact, at first I tried to use TypeSystem to find classes implementing HealthIndicator but it seems TypeSystem inspects only applications classes and not libraries classes.

This is what I've tried :


public class HealthContributorHints implements NativeConfiguration {

    @Override
    public List<HintDeclaration> computeHints(TypeSystem typeSystem) {
        Type healthIndicator = typeSystem.resolve("org/springframework/boot/actuate/health/HealthIndicator", true);
        if (healthIndicator != null) {
            List<Type> healthIndicatorSubTypes = healthIndicator.getSubtypes();
            HintDeclaration hintDeclaration = new HintDeclaration();
            for (Type subtype: healthIndicatorSubTypes) {
                hintDeclaration.addDependantType(subtype.getDottedName(), new AccessDescriptor(AccessBits.FULL_REFLECTION));
            }
            return Collections.singletonList(hintDeclaration);
        }
        return Collections.emptyList();
    }
}

But healthIndicatorSubTypes is always empty.

I am listening to your advices to update this PR :)

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Oct 25, 2021
@snicoll
Copy link
Contributor

snicoll commented Oct 25, 2021

OK cool. So the idea would be to create a HealthIndicatorNativeConfigurationProcessor class that implements BeanFactoryNativeConfigurationProcessor in the org.springframework.boot.actuate.health package of spring-aot.

That interface gives you access to the bean factory and configuration registry. You could, in the implementation, use beanFactory#getBeanNamesForType(HealthIndicator.class) to retrieve the bean definitions candidate. Then, based on the list, you could feed the registry. As far as I can see, only the constructor is required so you could use the appropriate flag to narrow down the list of reflective configuration (Flag.allDeclaredConstructors).

For testing, please check EndpointNativeConfigurationProcessorTests that shows how you can kick off a simple bean factory and assert that the native configuration registry is in the right state.

You need to register your implementation in spring.factories and then give it a try on your sample. Let me know how it goes!

@snicoll snicoll added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Oct 25, 2021
@olivierboudet olivierboudet marked this pull request as draft October 25, 2021 18:28
@olivierboudet
Copy link
Contributor Author

hello @snicoll I pushed a first try to infer health indicators but only DiskSpaceHealthIndicator and PingHealthIndicator seems to be registered in the bean factory.
I think DiskSpaceHealthIndicator is registered because there is a TypeHintin EndpointAutoConfigurationHints.
However I don't know why PingHealthIndicator is registered but not other indicators like MongoHealthIndicator.

Am I doing something wrong ?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Oct 26, 2021
@snicoll
Copy link
Contributor

snicoll commented Oct 26, 2021

Am I doing something wrong ?

Nothing that I could see from the code. These two indicators are usually exposed by default. Do you have mongo in the app you're trying and is it configured? If you don't, that's to be expected that it's not available (and therefore not registered for the app).

@olivierboudet
Copy link
Contributor Author

Yes I have an application with implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'. If I run it with ./gradlew bootRun I can see the mongodb status in /actuator/health
If I build it with ./gradlew bootBuildImage --debug and run it I have the same error as described in the issue :

Native reflection configuration for org.springframework.boot.actuate.mongo.MongoHealthIndicator.<init>(org.springframework.data.mongodb.core.MongoTemplate) is missing.

I think this is because the health indicator for mongodb is in fact a HealthContributor defined by MongoHealthContributorAutoConfiguration.
If I change my BeanFactoryNativeConfigurationProcessor to get all HealthContributor beans, the mongoHealthContributor is found. But in this case, I have another error on the instanciation of MongoDatabaseFactoryDependentConfiguration :

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mongoHealthContributor' defined in class path resource [org/springframework/boot/actuate/autoconfigure/mongo/MongoHealthContributorAutoConfiguration.class]: Unsatisfied dependency expressed through method 'mongoHealthContributor' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration.<init>()
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
        at org.springframework.boot.actuate.endpoint.annotation.HealthIndicatorNativeConfigurationProcessor.process(HealthIndicatorNativeConfigurationProcessor.java:27)
        at org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistrar.lambda$processBeanFactory$0(NativeConfigurationRegistrar.java:55)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
        at org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistrar.processBeanFactory(NativeConfigurationRegistrar.java:55)
        at org.springframework.aot.context.bootstrap.generator.ContextBootstrapGenerator.generateBootstrapMethod(ContextBootstrapGenerator.java:92)
        at org.springframework.aot.context.bootstrap.generator.ContextBootstrapGenerator.generateBootstrapClass(ContextBootstrapGenerator.java:79)
        at org.springframework.aot.context.bootstrap.ContextBootstrapContributor.contribute(ContextBootstrapContributor.java:80)
        at org.springframework.aot.BootstrapCodeGenerator.generate(BootstrapCodeGenerator.java:90)
        at org.springframework.aot.BootstrapCodeGenerator.generate(BootstrapCodeGenerator.java:70)
        at org.springframework.aot.context.bootstrap.GenerateBootstrap.call(GenerateBootstrap.java:105)
        at org.springframework.aot.context.bootstrap.GenerateBootstrap.call(GenerateBootstrap.java:44)
        at picocli.CommandLine.executeUserObject(CommandLine.java:1953)
        at picocli.CommandLine.access$1300(CommandLine.java:145)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2352)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2346)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2311)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
        at picocli.CommandLine.execute(CommandLine.java:2078)
        at org.springframework.aot.context.bootstrap.GenerateBootstrap.main(GenerateBootstrap.java:110)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration.<init>()
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1334)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:410)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1598)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1562)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1481)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1338)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
        ... 28 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration.<init>()
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326)
        ... 52 more
Caused by: java.lang.NoSuchMethodException: org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration.<init>()
        at java.base/java.lang.Class.getConstructor0(Class.java:3349)
        at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
        ... 53 more

As MongoDatabaseFactoryDependentConfiguration is not public, I can't set a hint for it.

@snicoll
Copy link
Contributor

snicoll commented Oct 26, 2021

I think this is because the health indicator for mongodb is in fact a HealthContributor defined by MongoHealthContributorAutoConfiguration.

Ah yes, sorry. That's what happens when you comment outside of an IDE. You should check for the parent interface indeed (HealthContributor).

But in this case, I have another error on the instanciation of

That's a separate problem. Can you please create an issue for that?

Let me know when the PR is ready with the contributor check or if you want me to take over. Thanks!

@olivierboudet olivierboudet marked this pull request as ready for review October 26, 2021 09:01
@snicoll snicoll changed the title Add hints for HealthIndicator classes (#1183) Add hints for HealthContributors Oct 26, 2021
@snicoll snicoll added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Oct 26, 2021
@snicoll snicoll self-assigned this Oct 26, 2021
@snicoll snicoll added this to the 0.11.0-M2 milestone Oct 26, 2021
@olivierboudet
Copy link
Contributor Author

The PR is ready with HealthContributor check.
And I opened #1189 for the issue on MongoDatabaseFactoryDependentConfiguration

snicoll pushed a commit that referenced this pull request Oct 26, 2021
snicoll added a commit that referenced this pull request Oct 26, 2021
@snicoll snicoll closed this in 3e32115 Oct 26, 2021
@snicoll
Copy link
Contributor

snicoll commented Oct 26, 2021

@olivierboudet thank you for making your first (code) contribution to Spring Native.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: enhancement A general enhancement
Development

Successfully merging this pull request may close these issues.

Missing hints for health indicators
4 participants