diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfiguration.java new file mode 100644 index 00000000000..1eef2335ecb --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfiguration.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.availability; + +import org.springframework.boot.actuate.availability.AvailabilityStateHealthIndicator; +import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator; +import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for + * {@link AvailabilityStateHealthIndicator}. + * vailabilityHealthContributorAutoConfigurationTests + * + * @author Brian Clozel + * @since 2.3.2 + */ +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(ApplicationAvailabilityAutoConfiguration.class) +public class AvailabilityHealthContributorAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.health.livenessstate", name = "enabled", havingValue = "true") + public LivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) { + return new LivenessStateHealthIndicator(applicationAvailability); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "management.health.readinessstate", name = "enabled", havingValue = "true") + public ReadinessStateHealthIndicator readinessStateHealthIndicator( + ApplicationAvailability applicationAvailability) { + return new ReadinessStateHealthIndicator(applicationAvailability); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfiguration.java index aea64fd36ee..2863b3c1b34 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.autoconfigure.availability; -import org.springframework.boot.actuate.autoconfigure.availability.AvailabilityProbesAutoConfiguration.ProbesCondition; -import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator; import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -44,22 +42,20 @@ import org.springframework.core.type.AnnotatedTypeMetadata; * @since 2.3.0 */ @Configuration(proxyBeanMethods = false) -@Conditional(ProbesCondition.class) -@AutoConfigureAfter(ApplicationAvailabilityAutoConfiguration.class) +@Conditional(AvailabilityProbesAutoConfiguration.ProbesCondition.class) +@AutoConfigureAfter({ AvailabilityHealthContributorAutoConfiguration.class, + ApplicationAvailabilityAutoConfiguration.class }) public class AvailabilityProbesAutoConfiguration { @Bean - @ConditionalOnEnabledHealthIndicator("livenessState") @ConditionalOnMissingBean - public LivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) { + public LivenessStateHealthIndicator livenessStateProbeIndicator(ApplicationAvailability applicationAvailability) { return new LivenessStateHealthIndicator(applicationAvailability); } @Bean - @ConditionalOnEnabledHealthIndicator("readinessState") @ConditionalOnMissingBean - public ReadinessStateHealthIndicator readinessStateHealthIndicator( - ApplicationAvailability applicationAvailability) { + public ReadinessStateHealthIndicator readinessStateProbeIndicator(ApplicationAvailability applicationAvailability) { return new ReadinessStateHealthIndicator(applicationAvailability); } @@ -70,20 +66,27 @@ public class AvailabilityProbesAutoConfiguration { /** * {@link SpringBootCondition} to enable or disable probes. + *
+ * Probes are enabled if the dedicated configuration property is enabled or if the + * Kubernetes cloud environment is detected/enforced. */ static class ProbesCondition extends SpringBootCondition { - private static final String ENABLED_PROPERTY = "management.health.probes.enabled"; + private static final String ENABLED_PROPERTY = "management.endpoint.health.probes.enabled"; + + private static final String DEPRECATED_ENABLED_PROPERTY = "management.health.probes.enabled"; @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); - ConditionMessage.Builder message = ConditionMessage.forCondition("Health availability"); - String enabled = environment.getProperty(ENABLED_PROPERTY); - if (enabled != null) { - boolean match = !"false".equalsIgnoreCase(enabled); - return new ConditionOutcome(match, - message.because("'" + ENABLED_PROPERTY + "' set to '" + enabled + "'")); + ConditionMessage.Builder message = ConditionMessage.forCondition("Probes availability"); + ConditionOutcome outcome = onProperty(environment, message, ENABLED_PROPERTY); + if (outcome != null) { + return outcome; + } + outcome = onProperty(environment, message, DEPRECATED_ENABLED_PROPERTY); + if (outcome != null) { + return outcome; } if (CloudPlatform.getActive(environment) == CloudPlatform.KUBERNETES) { return ConditionOutcome.match(message.because("running on Kubernetes")); @@ -91,6 +94,16 @@ public class AvailabilityProbesAutoConfiguration { return ConditionOutcome.noMatch(message.because("not running on a supported cloud platform")); } + private ConditionOutcome onProperty(Environment environment, ConditionMessage.Builder message, + String propertyName) { + String enabled = environment.getProperty(propertyName); + if (enabled != null) { + boolean match = !"false".equalsIgnoreCase(enabled); + return new ConditionOutcome(match, message.because("'" + propertyName + "' set to '" + enabled + "'")); + } + return null; + } + } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 6d8d00e4251..5f7c1faae25 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -47,6 +47,12 @@ "sun.java.command" ] }, + { + "name": "management.endpoint.health.probes.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable liveness and readiness probes.", + "defaultValue": false + }, { "name": "management.endpoint.health.show-details", "defaultValue": "never" @@ -168,6 +174,12 @@ "description": "Whether to enable LDAP health check.", "defaultValue": true }, + { + "name": "management.health.livenessstate.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable liveness state health check.", + "defaultValue": false + }, { "name": "management.health.mail.enabled", "type": "java.lang.Boolean", @@ -196,7 +208,10 @@ "name": "management.health.probes.enabled", "type": "java.lang.Boolean", "description": "Whether to enable liveness and readiness probes.", - "defaultValue": false + "defaultValue": false, + "deprecation": { + "replacement": "management.endpoint.health.probes.enabled" + } }, { "name": "management.health.rabbit.enabled", @@ -204,6 +219,12 @@ "description": "Whether to enable RabbitMQ health check.", "defaultValue": true }, + { + "name": "management.health.readynessstate.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable readiness state health check.", + "defaultValue": false + }, { "name": "management.health.redis.enabled", "type": "java.lang.Boolean", diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 5327c6df9be..d9832a774b6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.availability.AvailabilityHealthContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.availability.AvailabilityProbesAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfigurationTests.java new file mode 100644 index 00000000000..9ff3b57753b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityHealthContributorAutoConfigurationTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.availability; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator; +import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link AvailabilityHealthContributorAutoConfiguration} + * + * @author Brian Clozel + */ +class AvailabilityHealthContributorAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations + .of(ApplicationAvailabilityAutoConfiguration.class, AvailabilityHealthContributorAutoConfiguration.class)); + + @Test + void probesWhenNotKubernetesAddsNoBeans() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class) + .doesNotHaveBean(LivenessStateHealthIndicator.class) + .doesNotHaveBean(ReadinessStateHealthIndicator.class)); + } + + @Test + void livenessIndicatorWhenPropertyEnabledAddsBeans() { + this.contextRunner.withPropertyValues("management.health.livenessState.enabled=true") + .run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class) + .hasSingleBean(LivenessStateHealthIndicator.class) + .doesNotHaveBean(ReadinessStateHealthIndicator.class)); + } + + @Test + void readinessIndicatorWhenPropertyEnabledAddsBeans() { + this.contextRunner.withPropertyValues("management.health.readinessState.enabled=true") + .run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class) + .hasSingleBean(ReadinessStateHealthIndicator.class) + .doesNotHaveBean(LivenessStateHealthIndicator.class)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfigurationTests.java index 59e78bb1053..f44b8389d3a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfigurationTests.java @@ -34,8 +34,9 @@ import static org.assertj.core.api.Assertions.assertThat; */ class AvailabilityProbesAutoConfigurationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations - .of(ApplicationAvailabilityAutoConfiguration.class, AvailabilityProbesAutoConfiguration.class)); + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(ApplicationAvailabilityAutoConfiguration.class, + AvailabilityHealthContributorAutoConfiguration.class, AvailabilityProbesAutoConfiguration.class)); @Test void probesWhenNotKubernetesAddsNoBeans() { @@ -56,7 +57,7 @@ class AvailabilityProbesAutoConfigurationTests { @Test void probesWhenPropertyEnabledAddsBeans() { - this.contextRunner.withPropertyValues("management.health.probes.enabled=true") + this.contextRunner.withPropertyValues("management.endpoint.health.probes.enabled=true") .run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class) .hasSingleBean(LivenessStateHealthIndicator.class) .hasSingleBean(ReadinessStateHealthIndicator.class) @@ -66,7 +67,8 @@ class AvailabilityProbesAutoConfigurationTests { @Test void probesWhenKubernetesAndPropertyDisabledAddsNotBeans() { this.contextRunner - .withPropertyValues("spring.main.cloud-platform=kubernetes", "management.health.probes.enabled=false") + .withPropertyValues("spring.main.cloud-platform=kubernetes", + "management.endpoint.health.probes.enabled=false") .run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class) .doesNotHaveBean(LivenessStateHealthIndicator.class) .doesNotHaveBean(ReadinessStateHealthIndicator.class) diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc index 9a8b398baa2..b2cf750092e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc @@ -712,6 +712,20 @@ The following `HealthIndicators` are auto-configured by Spring Boot when appropr TIP: You can disable them all by setting the configprop:management.health.defaults.enabled[] property. +Additional `HealthIndicators` are available but not enabled by default; +developers can use their configuration property to activate them: + +[cols="4,6"] +|=== +| Name | Description + +| {spring-boot-actuator-module-code}/availability/LivenessStateHealthIndicator.java[`LivenessStateHealthIndicator`] +| Checks the liveness state of the application. + +| {spring-boot-actuator-module-code}/availability/ReadinessStateHealthIndicator.java[`ReadinessStateHealthIndicator`] +| Checks the readiness state of the application. +|=== + ==== Writing Custom HealthIndicators