Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Health Web Endpoint Extension Failed to Initialize When Some Conditions Hit #29532

Closed
leovx opened this issue Jan 22, 2022 · 4 comments
Closed
Assignees
Labels
type: bug A general bug
Milestone

Comments

@leovx
Copy link

leovx commented Jan 22, 2022

Dear all,
I just encountered a framework bug, details below. Let's together figure out the most neat way to handle it. :)

Trigger Conditions

  1. Running on Cloud Foundry environment
  2. Using Spring Boot Actuator 2.6.x (Current latest = 2.6.2)
  3. In your config file, manually include some endpoints but not 'health'

Related Issues:

#28389
#25471
#28131

My Project to Replay the Bug and Temp Solution

https://github.com/leovx/spring-boot-actuator-pcf-bug-demo

Error log

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'healthEndpointWebMvcHandlerMapping' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping]: Factory method 'healthEndpointWebMvcHandlerMapping' threw exception; nested exception is java.util.NoSuchElementException: No value present
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.14.jar:5.3.14]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.14.jar:5.3.14]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.2.jar:2.6.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290) ~[spring-boot-2.6.2.jar:2.6.2]
    at com.jinghao.demo.DemoApplication.main(DemoApplication.java:10) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping]: Factory method 'healthEndpointWebMvcHandlerMapping' threw exception; nested exception is java.util.NoSuchElementException: No value present
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.14.jar:5.3.14]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.14.jar:5.3.14]
    ... 19 common frames omitted
Caused by: java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:143) ~[na:na]
    at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:81) ~[spring-boot-actuator-autoconfigure-2.6.2.jar:2.6.2]
    at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.access$000(HealthEndpointWebExtensionConfiguration.java:69) ~[spring-boot-actuator-autoconfigure-2.6.2.jar:2.6.2]
    at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:90) ~[spring-boot-actuator-autoconfigure-2.6.2.jar:2.6.2]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.14.jar:5.3.14]
    ... 20 common frames omitted
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 22, 2022
@bclozel bclozel assigned bclozel and unassigned bclozel Jan 24, 2022
@bclozel bclozel added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 24, 2022
@bclozel bclozel added this to the 2.6.x milestone Jan 24, 2022
@leovx
Copy link
Author

leovx commented Jan 24, 2022

Spring Boot 2.6.3 has been confirmed to have the bug.

@bclozel
Copy link
Member

bclozel commented Jan 24, 2022

I've reproduced the issue with the sample provided by @leovx (thanks! that was super useful!).

To summarize: an application that selectively enables web endpoints (but not the health one) in its application.properties and deployed on CloudFoundry fails with the exception above.

What happens is:

The OnAvailableEndpointCondition always matches for a CloudPlatform.CLOUD_FOUNDRY environment. So @ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = {EndpointExposure.WEB}) on HealthEndpointWebExtensionConfiguration matches in this case.

In the same class, org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.MvcAdditionalHealthEndpointPathsConfiguration#healthEndpointWebMvcHandlerMapping fails because the injected WebEndpointsSupplier is an instance of WebEndpointDiscoverer and it does not contain the health endpoint.

All the CloudFoundry setup is done in org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration#cloudFoundryWebEndpointServletHandlerMapping.

The condition should be probably revisited with this use case in mind.

@mbhave mbhave self-assigned this Jan 25, 2022
@leovx
Copy link
Author

leovx commented Jan 25, 2022

Thanks @bclozel. To add up, some teams might not want to use PCF health, but the vanilla one. Hence they might have below setting set to false, which would disable CloudFoundryActuatorAutoConfiguration during boot up.

management.cloudfoundry.enabled=false

@mbhave Please do let me know what you think about the fix we can do in Spring Boot framework. I am pretty curious about the fix, though not yet have time to read through the whole Actuator codebase.

Appreciated. :D

@izeye
Copy link
Contributor

izeye commented Jan 29, 2022

This seems to belong to the 2.6.4 milestone.

@bclozel bclozel modified the milestones: 2.6.x, 2.6.4 Jan 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants