Skip to content

Commit fe807d6

Browse files
committed
Improve liveness/readiness health config
Prior to this commit, the application availability infrastructure would mix the `AvailabilityState`, the `HealthIndicator` and the `HealthGroup` concepts and would not align with the rest. This commit auto-configures the livenessState and readinessState health indicators with the relevant configuration properties. Unlike other indicators, they are not enabled by default but might be in future versions. This also moves the `management.health.probes.enabled` property to `management.endpoint.health.probes.enabled` since "probes" here is not a health indicator but rather a configuration flag for the health endpoint. Finally, the probes auto-configuration is refined to automatically add liveness and readiness indicators for the probes group if they're not already present. Closes gh-22107
1 parent cb73558 commit fe807d6

File tree

7 files changed

+193
-21
lines changed

7 files changed

+193
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.availability;
18+
19+
import org.springframework.boot.actuate.availability.AvailabilityStateHealthIndicator;
20+
import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator;
21+
import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator;
22+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
23+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
24+
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27+
import org.springframework.boot.availability.ApplicationAvailability;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
31+
/**
32+
* {@link EnableAutoConfiguration Auto-configuration} for
33+
* {@link AvailabilityStateHealthIndicator}.
34+
* vailabilityHealthContributorAutoConfigurationTests
35+
*
36+
* @author Brian Clozel
37+
* @since 2.3.2
38+
*/
39+
@Configuration(proxyBeanMethods = false)
40+
@AutoConfigureAfter(ApplicationAvailabilityAutoConfiguration.class)
41+
public class AvailabilityHealthContributorAutoConfiguration {
42+
43+
@Bean
44+
@ConditionalOnMissingBean
45+
@ConditionalOnProperty(prefix = "management.health.livenessstate", name = "enabled", havingValue = "true")
46+
public LivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) {
47+
return new LivenessStateHealthIndicator(applicationAvailability);
48+
}
49+
50+
@Bean
51+
@ConditionalOnMissingBean
52+
@ConditionalOnProperty(prefix = "management.health.readinessstate", name = "enabled", havingValue = "true")
53+
public ReadinessStateHealthIndicator readinessStateHealthIndicator(
54+
ApplicationAvailability applicationAvailability) {
55+
return new ReadinessStateHealthIndicator(applicationAvailability);
56+
}
57+
58+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfiguration.java

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.availability;
1818

19-
import org.springframework.boot.actuate.autoconfigure.availability.AvailabilityProbesAutoConfiguration.ProbesCondition;
20-
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
2119
import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator;
2220
import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator;
2321
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -44,22 +42,20 @@
4442
* @since 2.3.0
4543
*/
4644
@Configuration(proxyBeanMethods = false)
47-
@Conditional(ProbesCondition.class)
48-
@AutoConfigureAfter(ApplicationAvailabilityAutoConfiguration.class)
45+
@Conditional(AvailabilityProbesAutoConfiguration.ProbesCondition.class)
46+
@AutoConfigureAfter({ AvailabilityHealthContributorAutoConfiguration.class,
47+
ApplicationAvailabilityAutoConfiguration.class })
4948
public class AvailabilityProbesAutoConfiguration {
5049

5150
@Bean
52-
@ConditionalOnEnabledHealthIndicator("livenessState")
5351
@ConditionalOnMissingBean
54-
public LivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) {
52+
public LivenessStateHealthIndicator livenessStateProbeIndicator(ApplicationAvailability applicationAvailability) {
5553
return new LivenessStateHealthIndicator(applicationAvailability);
5654
}
5755

5856
@Bean
59-
@ConditionalOnEnabledHealthIndicator("readinessState")
6057
@ConditionalOnMissingBean
61-
public ReadinessStateHealthIndicator readinessStateHealthIndicator(
62-
ApplicationAvailability applicationAvailability) {
58+
public ReadinessStateHealthIndicator readinessStateProbeIndicator(ApplicationAvailability applicationAvailability) {
6359
return new ReadinessStateHealthIndicator(applicationAvailability);
6460
}
6561

@@ -70,27 +66,44 @@ public AvailabilityProbesHealthEndpointGroupsPostProcessor availabilityProbesHea
7066

7167
/**
7268
* {@link SpringBootCondition} to enable or disable probes.
69+
* <p>
70+
* Probes are enabled if the dedicated configuration property is enabled or if the
71+
* Kubernetes cloud environment is detected/enforced.
7372
*/
7473
static class ProbesCondition extends SpringBootCondition {
7574

76-
private static final String ENABLED_PROPERTY = "management.health.probes.enabled";
75+
private static final String ENABLED_PROPERTY = "management.endpoint.health.probes.enabled";
76+
77+
private static final String DEPRECATED_ENABLED_PROPERTY = "management.health.probes.enabled";
7778

7879
@Override
7980
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
8081
Environment environment = context.getEnvironment();
81-
ConditionMessage.Builder message = ConditionMessage.forCondition("Health availability");
82-
String enabled = environment.getProperty(ENABLED_PROPERTY);
83-
if (enabled != null) {
84-
boolean match = !"false".equalsIgnoreCase(enabled);
85-
return new ConditionOutcome(match,
86-
message.because("'" + ENABLED_PROPERTY + "' set to '" + enabled + "'"));
82+
ConditionMessage.Builder message = ConditionMessage.forCondition("Probes availability");
83+
ConditionOutcome outcome = onProperty(environment, message, ENABLED_PROPERTY);
84+
if (outcome != null) {
85+
return outcome;
86+
}
87+
outcome = onProperty(environment, message, DEPRECATED_ENABLED_PROPERTY);
88+
if (outcome != null) {
89+
return outcome;
8790
}
8891
if (CloudPlatform.getActive(environment) == CloudPlatform.KUBERNETES) {
8992
return ConditionOutcome.match(message.because("running on Kubernetes"));
9093
}
9194
return ConditionOutcome.noMatch(message.because("not running on a supported cloud platform"));
9295
}
9396

97+
private ConditionOutcome onProperty(Environment environment, ConditionMessage.Builder message,
98+
String propertyName) {
99+
String enabled = environment.getProperty(propertyName);
100+
if (enabled != null) {
101+
boolean match = !"false".equalsIgnoreCase(enabled);
102+
return new ConditionOutcome(match, message.because("'" + propertyName + "' set to '" + enabled + "'"));
103+
}
104+
return null;
105+
}
106+
94107
}
95108

96109
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
"sun.java.command"
4848
]
4949
},
50+
{
51+
"name": "management.endpoint.health.probes.enabled",
52+
"type": "java.lang.Boolean",
53+
"description": "Whether to enable liveness and readiness probes.",
54+
"defaultValue": false
55+
},
5056
{
5157
"name": "management.endpoint.health.show-details",
5258
"defaultValue": "never"
@@ -168,6 +174,12 @@
168174
"description": "Whether to enable LDAP health check.",
169175
"defaultValue": true
170176
},
177+
{
178+
"name": "management.health.livenessstate.enabled",
179+
"type": "java.lang.Boolean",
180+
"description": "Whether to enable liveness state health check.",
181+
"defaultValue": false
182+
},
171183
{
172184
"name": "management.health.mail.enabled",
173185
"type": "java.lang.Boolean",
@@ -196,14 +208,23 @@
196208
"name": "management.health.probes.enabled",
197209
"type": "java.lang.Boolean",
198210
"description": "Whether to enable liveness and readiness probes.",
199-
"defaultValue": false
211+
"defaultValue": false,
212+
"deprecation": {
213+
"replacement": "management.endpoint.health.probes.enabled"
214+
}
200215
},
201216
{
202217
"name": "management.health.rabbit.enabled",
203218
"type": "java.lang.Boolean",
204219
"description": "Whether to enable RabbitMQ health check.",
205220
"defaultValue": true
206221
},
222+
{
223+
"name": "management.health.readynessstate.enabled",
224+
"type": "java.lang.Boolean",
225+
"description": "Whether to enable readiness state health check.",
226+
"defaultValue": false
227+
},
207228
{
208229
"name": "management.health.redis.enabled",
209230
"type": "java.lang.Boolean",

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
22
org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthContributorAutoConfiguration,\
33
org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\
44
org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration,\
5+
org.springframework.boot.actuate.autoconfigure.availability.AvailabilityHealthContributorAutoConfiguration,\
56
org.springframework.boot.actuate.autoconfigure.availability.AvailabilityProbesAutoConfiguration,\
67
org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\
78
org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.availability;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator;
22+
import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator;
23+
import org.springframework.boot.autoconfigure.AutoConfigurations;
24+
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
25+
import org.springframework.boot.availability.ApplicationAvailability;
26+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* Tests for {@link AvailabilityHealthContributorAutoConfiguration}
32+
*
33+
* @author Brian Clozel
34+
*/
35+
class AvailabilityHealthContributorAutoConfigurationTests {
36+
37+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
38+
.of(ApplicationAvailabilityAutoConfiguration.class, AvailabilityHealthContributorAutoConfiguration.class));
39+
40+
@Test
41+
void probesWhenNotKubernetesAddsNoBeans() {
42+
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
43+
.doesNotHaveBean(LivenessStateHealthIndicator.class)
44+
.doesNotHaveBean(ReadinessStateHealthIndicator.class));
45+
}
46+
47+
@Test
48+
void livenessIndicatorWhenPropertyEnabledAddsBeans() {
49+
this.contextRunner.withPropertyValues("management.health.livenessState.enabled=true")
50+
.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
51+
.hasSingleBean(LivenessStateHealthIndicator.class)
52+
.doesNotHaveBean(ReadinessStateHealthIndicator.class));
53+
}
54+
55+
@Test
56+
void readinessIndicatorWhenPropertyEnabledAddsBeans() {
57+
this.contextRunner.withPropertyValues("management.health.readinessState.enabled=true")
58+
.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
59+
.hasSingleBean(ReadinessStateHealthIndicator.class)
60+
.doesNotHaveBean(LivenessStateHealthIndicator.class));
61+
}
62+
63+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/availability/AvailabilityProbesAutoConfigurationTests.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
*/
3535
class AvailabilityProbesAutoConfigurationTests {
3636

37-
private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
38-
.of(ApplicationAvailabilityAutoConfiguration.class, AvailabilityProbesAutoConfiguration.class));
37+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
38+
.withConfiguration(AutoConfigurations.of(ApplicationAvailabilityAutoConfiguration.class,
39+
AvailabilityHealthContributorAutoConfiguration.class, AvailabilityProbesAutoConfiguration.class));
3940

4041
@Test
4142
void probesWhenNotKubernetesAddsNoBeans() {
@@ -56,7 +57,7 @@ void probesWhenKubernetesAddsBeans() {
5657

5758
@Test
5859
void probesWhenPropertyEnabledAddsBeans() {
59-
this.contextRunner.withPropertyValues("management.health.probes.enabled=true")
60+
this.contextRunner.withPropertyValues("management.endpoint.health.probes.enabled=true")
6061
.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
6162
.hasSingleBean(LivenessStateHealthIndicator.class)
6263
.hasSingleBean(ReadinessStateHealthIndicator.class)
@@ -66,7 +67,8 @@ void probesWhenPropertyEnabledAddsBeans() {
6667
@Test
6768
void probesWhenKubernetesAndPropertyDisabledAddsNotBeans() {
6869
this.contextRunner
69-
.withPropertyValues("spring.main.cloud-platform=kubernetes", "management.health.probes.enabled=false")
70+
.withPropertyValues("spring.main.cloud-platform=kubernetes",
71+
"management.endpoint.health.probes.enabled=false")
7072
.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
7173
.doesNotHaveBean(LivenessStateHealthIndicator.class)
7274
.doesNotHaveBean(ReadinessStateHealthIndicator.class)

spring-boot-project/spring-boot-docs/src/docs/asciidoc/production-ready-features.adoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,20 @@ The following `HealthIndicators` are auto-configured by Spring Boot when appropr
712712

713713
TIP: You can disable them all by setting the configprop:management.health.defaults.enabled[] property.
714714

715+
Additional `HealthIndicators` are available but not enabled by default;
716+
developers can use their configuration property to activate them:
717+
718+
[cols="4,6"]
719+
|===
720+
| Name | Description
721+
722+
| {spring-boot-actuator-module-code}/availability/LivenessStateHealthIndicator.java[`LivenessStateHealthIndicator`]
723+
| Checks the liveness state of the application.
724+
725+
| {spring-boot-actuator-module-code}/availability/ReadinessStateHealthIndicator.java[`ReadinessStateHealthIndicator`]
726+
| Checks the readiness state of the application.
727+
|===
728+
715729

716730

717731
==== Writing Custom HealthIndicators

0 commit comments

Comments
 (0)