Rename probe health indicators
Rename `LivenessProbeHealthIndicator` to `LivenessStateHealthIndicator` and `ReadinessProbeHealthIndicator` to `ReadinessStateHealthIndicator`. Also introduce a general purpose `AvailabilityStateHealthIndicator` class. See gh-20962
This commit is contained in:
@@ -18,8 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.kubernetes;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.kubernetes.ProbesHealthContributorAutoConfiguration.KubernetesOrPropertyCondition;
|
||||
import org.springframework.boot.actuate.availability.LivenessProbeHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.ReadinessProbeHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroupsRegistryCustomizer;
|
||||
import org.springframework.boot.actuate.kubernetes.ProbesHealthEndpointGroupsRegistrar;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
@@ -37,7 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||
* {@link LivenessProbeHealthIndicator} and {@link ReadinessProbeHealthIndicator}.
|
||||
* {@link LivenessStateHealthIndicator} and {@link ReadinessStateHealthIndicator}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 2.3.0
|
||||
@@ -50,16 +50,16 @@ public class ProbesHealthContributorAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnEnabledHealthIndicator("livenessProbe")
|
||||
@ConditionalOnMissingBean
|
||||
public LivenessProbeHealthIndicator livenessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
|
||||
return new LivenessProbeHealthIndicator(applicationAvailability);
|
||||
public LivenessStateHealthIndicator livenessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
|
||||
return new LivenessStateHealthIndicator(applicationAvailability);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledHealthIndicator("readinessProbe")
|
||||
@ConditionalOnMissingBean
|
||||
public ReadinessProbeHealthIndicator readinessProbeHealthIndicator(
|
||||
public ReadinessStateHealthIndicator readinessProbeHealthIndicator(
|
||||
ApplicationAvailability applicationAvailability) {
|
||||
return new ReadinessProbeHealthIndicator(applicationAvailability);
|
||||
return new ReadinessStateHealthIndicator(applicationAvailability);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.kubernetes;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.availability.LivenessProbeHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.ReadinessProbeHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator;
|
||||
import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroupsRegistryCustomizer;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
|
||||
@@ -29,7 +29,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests fos {@link ProbesHealthContributorAutoConfiguration}.
|
||||
* Tests for {@link ProbesHealthContributorAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@@ -41,8 +41,8 @@ class ProbesHealthContributorAutoConfigurationTests {
|
||||
@Test
|
||||
void probesNotConfiguredIfNotKubernetes() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
|
||||
.doesNotHaveBean(LivenessProbeHealthIndicator.class)
|
||||
.doesNotHaveBean(ReadinessProbeHealthIndicator.class)
|
||||
.doesNotHaveBean(LivenessStateHealthIndicator.class)
|
||||
.doesNotHaveBean(ReadinessStateHealthIndicator.class)
|
||||
.doesNotHaveBean(HealthEndpointGroupsRegistryCustomizer.class));
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ class ProbesHealthContributorAutoConfigurationTests {
|
||||
void probesConfiguredIfProperty() {
|
||||
this.contextRunner.withPropertyValues("management.health.probes.enabled=true")
|
||||
.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)
|
||||
.hasSingleBean(LivenessProbeHealthIndicator.class)
|
||||
.hasSingleBean(ReadinessProbeHealthIndicator.class)
|
||||
.hasSingleBean(LivenessStateHealthIndicator.class)
|
||||
.hasSingleBean(ReadinessStateHealthIndicator.class)
|
||||
.hasSingleBean(HealthEndpointGroupsRegistryCustomizer.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.availability;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} that checks a specific {@link AvailabilityState} of the
|
||||
* application.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Brian Clozel
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class AvailabilityStateHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private final ApplicationAvailability applicationAvailability;
|
||||
|
||||
private Class<? extends AvailabilityState> stateType;
|
||||
|
||||
private final Map<AvailabilityState, Status> statusMappings = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new {@link AvailabilityStateHealthIndicator} instance.
|
||||
* @param <S> the availability state type
|
||||
* @param applicationAvailability the application availability
|
||||
* @param stateType the availability state type
|
||||
* @param statusMappings consumer used to setup the status mappings
|
||||
*/
|
||||
public <S extends AvailabilityState> AvailabilityStateHealthIndicator(
|
||||
ApplicationAvailability applicationAvailability, Class<S> stateType,
|
||||
Consumer<StatusMappings<S>> statusMappings) {
|
||||
Assert.notNull(applicationAvailability, "ApplicationAvailability must not be null");
|
||||
Assert.notNull(stateType, "StateType must not be null");
|
||||
Assert.notNull(statusMappings, "StatusMappings must not be null");
|
||||
this.applicationAvailability = applicationAvailability;
|
||||
this.stateType = stateType;
|
||||
statusMappings.accept(this.statusMappings::put);
|
||||
assertAllEnumsMapped(stateType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <S extends AvailabilityState> void assertAllEnumsMapped(Class<S> stateType) {
|
||||
if (!this.statusMappings.containsKey(null) && Enum.class.isAssignableFrom(stateType)) {
|
||||
EnumSet elements = EnumSet.allOf((Class) stateType);
|
||||
for (Object element : elements) {
|
||||
Assert.isTrue(this.statusMappings.containsKey(element), "StatusMappings does not include " + element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Builder builder) throws Exception {
|
||||
AvailabilityState state = getState(this.applicationAvailability);
|
||||
Status status = this.statusMappings.get(state);
|
||||
if (status == null) {
|
||||
status = this.statusMappings.get(null);
|
||||
}
|
||||
Assert.state(status != null, "No mapping provided for " + state);
|
||||
builder.status(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current availability state. Subclasses can override this method if a
|
||||
* different retrieval mechanism is needed.
|
||||
* @param applicationAvailability the application availability
|
||||
* @return the current availability state
|
||||
*/
|
||||
protected AvailabilityState getState(ApplicationAvailability applicationAvailability) {
|
||||
return applicationAvailability.getState(this.stateType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used to add status mappings.
|
||||
*
|
||||
* @param <S> the availability state type
|
||||
*/
|
||||
public interface StatusMappings<S extends AvailabilityState> {
|
||||
|
||||
/**
|
||||
* Add the status that should be used if no explicit mapping is defined.
|
||||
* @param status the default status
|
||||
*/
|
||||
default void addDefaultStatus(Status status) {
|
||||
add(null, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new status mapping .
|
||||
* @param availabilityState the availability state
|
||||
* @param status the mapped status
|
||||
*/
|
||||
void add(S availabilityState, Status status);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
package org.springframework.boot.actuate.availability;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
|
||||
/**
|
||||
@@ -29,18 +28,18 @@ import org.springframework.boot.availability.LivenessState;
|
||||
* @author Brian Clozel
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class LivenessProbeHealthIndicator extends AbstractHealthIndicator {
|
||||
public class LivenessStateHealthIndicator extends AvailabilityStateHealthIndicator {
|
||||
|
||||
private final ApplicationAvailability applicationAvailability;
|
||||
|
||||
public LivenessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
|
||||
this.applicationAvailability = applicationAvailability;
|
||||
public LivenessStateHealthIndicator(ApplicationAvailability availability) {
|
||||
super(availability, LivenessState.class, (statusMappings) -> {
|
||||
statusMappings.add(LivenessState.CORRECT, Status.UP);
|
||||
statusMappings.add(LivenessState.BROKEN, Status.DOWN);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
LivenessState state = this.applicationAvailability.getLivenessState();
|
||||
builder.status(LivenessState.CORRECT == state ? Status.UP : Status.DOWN);
|
||||
protected AvailabilityState getState(ApplicationAvailability applicationAvailability) {
|
||||
return applicationAvailability.getLivenessState();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,31 +16,32 @@
|
||||
|
||||
package org.springframework.boot.actuate.availability;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
import org.springframework.boot.availability.ReadinessState;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} that checks the {@link ReadinessState} of the application.
|
||||
* A {@link HealthIndicator} that checks the {@link LivenessState} of the application.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Phillip Webb
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public class ReadinessProbeHealthIndicator extends AbstractHealthIndicator {
|
||||
public class ReadinessStateHealthIndicator extends AvailabilityStateHealthIndicator {
|
||||
|
||||
private final ApplicationAvailability applicationAvailability;
|
||||
|
||||
public ReadinessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
|
||||
this.applicationAvailability = applicationAvailability;
|
||||
public ReadinessStateHealthIndicator(ApplicationAvailability availability) {
|
||||
super(availability, ReadinessState.class, (statusMappings) -> {
|
||||
statusMappings.add(ReadinessState.ACCEPTING_TRAFFIC, Status.UP);
|
||||
statusMappings.add(ReadinessState.REFUSING_TRAFFIC, Status.OUT_OF_SERVICE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
ReadinessState state = this.applicationAvailability.getReadinessState();
|
||||
builder.status(ReadinessState.ACCEPTING_TRAFFIC == state ? Status.UP : Status.OUT_OF_SERVICE);
|
||||
protected AvailabilityState getState(ApplicationAvailability applicationAvailability) {
|
||||
return applicationAvailability.getReadinessState();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.availability;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Tests for {@link AvailabilityStateHealthIndicator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AvailabilityStateHealthIndicatorTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationAvailability applicationAvailability;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenApplicationAvailabilityIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AvailabilityStateHealthIndicator(null, LivenessState.class, (statusMappings) -> {
|
||||
})).withMessage("ApplicationAvailability must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenStateTypeIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new AvailabilityStateHealthIndicator(this.applicationAvailability, null, (statusMappings) -> {
|
||||
})).withMessage("StateType must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenStatusMappingIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(
|
||||
() -> new AvailabilityStateHealthIndicator(this.applicationAvailability, LivenessState.class, null))
|
||||
.withMessage("StatusMappings must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenStatusMappingDoesNotCoverAllEnumsThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AvailabilityStateHealthIndicator(this.applicationAvailability,
|
||||
LivenessState.class, (statusMappings) -> statusMappings.add(LivenessState.CORRECT, Status.UP)))
|
||||
.withMessage("StatusMappings does not include BROKEN");
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthReturnsMappedStatus() {
|
||||
AvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,
|
||||
LivenessState.class, (statusMappings) -> {
|
||||
statusMappings.add(LivenessState.CORRECT, Status.UP);
|
||||
statusMappings.add(LivenessState.BROKEN, Status.DOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthReturnsDefaultStatus() {
|
||||
AvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,
|
||||
LivenessState.class, (statusMappings) -> {
|
||||
statusMappings.add(LivenessState.CORRECT, Status.UP);
|
||||
statusMappings.addDefaultStatus(Status.UNKNOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenNotEnumReturnsMappedStatus() {
|
||||
AvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,
|
||||
TestAvailabilityState.class, (statusMappings) -> {
|
||||
statusMappings.add(TestAvailabilityState.ONE, Status.UP);
|
||||
statusMappings.addDefaultStatus(Status.DOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(TestAvailabilityState.class)).willReturn(TestAvailabilityState.TWO);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
}
|
||||
|
||||
static class TestAvailabilityState implements AvailabilityState {
|
||||
|
||||
static final TestAvailabilityState ONE = new TestAvailabilityState();
|
||||
|
||||
static final TestAvailabilityState TWO = new TestAvailabilityState();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,20 +28,20 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link LivenessProbeHealthIndicator}
|
||||
* Tests for {@link LivenessStateHealthIndicator}
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class LivenessProbeHealthIndicatorTests {
|
||||
class LivenessStateHealthIndicatorTests {
|
||||
|
||||
private ApplicationAvailability availability;
|
||||
|
||||
private LivenessProbeHealthIndicator healthIndicator;
|
||||
private LivenessStateHealthIndicator healthIndicator;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.availability = mock(ApplicationAvailability.class);
|
||||
this.healthIndicator = new LivenessProbeHealthIndicator(this.availability);
|
||||
this.healthIndicator = new LivenessStateHealthIndicator(this.availability);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -28,20 +28,20 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReadinessProbeHealthIndicator}
|
||||
* Tests for {@link ReadinessStateHealthIndicator}
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class ReadinessProbeHealthIndicatorTests {
|
||||
class ReadinessStateHealthIndicatorTests {
|
||||
|
||||
private ApplicationAvailability availability;
|
||||
|
||||
private ReadinessProbeHealthIndicator healthIndicator;
|
||||
private ReadinessStateHealthIndicator healthIndicator;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.availability = mock(ApplicationAvailability.class);
|
||||
this.healthIndicator = new ReadinessProbeHealthIndicator(this.availability);
|
||||
this.healthIndicator = new ReadinessStateHealthIndicator(this.availability);
|
||||
}
|
||||
|
||||
@Test
|
||||
Reference in New Issue
Block a user