Allow custom availability states

Create a general purpose `AvailabilityState` interface and refactor
the existing `LivenessState` and `ReadinessState` to use it. A single
`AvailabilityChangeEvent` is now used to carry all availability state
updates.

This commit also renames `ApplicationAvailabilityProvider` to
`ApplicationAvailabilityBean` and extracts an `ApplicationAvailability`
interface that other beans can inject. The helps to hide the event
listener method, which is really internal.

Finally the state enums have been renamed as follows:

 - `LivenessState.LIVE` -> `LivenessState.CORRECT`
 - `ReadinessState.READY` -> `ReadinessState.ACCEPTING_TRAFFIC`
 - `ReadinessState.UNREADY` -> `ReadinessState.REFUSING_TRAFFIC`

See gh-20962
This commit is contained in:
Phillip Webb
2020-04-09 16:04:25 -07:00
parent 473d4fd73d
commit bb79c847b2
26 changed files with 561 additions and 369 deletions

View File

@@ -19,7 +19,8 @@ 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.availability.ApplicationAvailabilityProvider;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.LivenessState;
/**
@@ -30,20 +31,16 @@ import org.springframework.boot.availability.LivenessState;
*/
public class LivenessProbeHealthIndicator extends AbstractHealthIndicator {
private final ApplicationAvailabilityProvider applicationAvailabilityProvider;
private final ApplicationAvailability applicationAvailability;
public LivenessProbeHealthIndicator(ApplicationAvailabilityProvider applicationAvailabilityProvider) {
this.applicationAvailabilityProvider = applicationAvailabilityProvider;
public LivenessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
this.applicationAvailability = applicationAvailability;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
if (LivenessState.LIVE.equals(this.applicationAvailabilityProvider.getLivenessState())) {
builder.up();
}
else {
builder.down();
}
LivenessState state = this.applicationAvailability.getLivenessState();
builder.status(LivenessState.CORRECT == state ? Status.UP : Status.DOWN);
}
}

View File

@@ -19,7 +19,8 @@ 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.availability.ApplicationAvailabilityProvider;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.ReadinessState;
/**
@@ -30,20 +31,16 @@ import org.springframework.boot.availability.ReadinessState;
*/
public class ReadinessProbeHealthIndicator extends AbstractHealthIndicator {
private final ApplicationAvailabilityProvider applicationAvailabilityProvider;
private final ApplicationAvailability applicationAvailability;
public ReadinessProbeHealthIndicator(ApplicationAvailabilityProvider applicationAvailabilityProvider) {
this.applicationAvailabilityProvider = applicationAvailabilityProvider;
public ReadinessProbeHealthIndicator(ApplicationAvailability applicationAvailability) {
this.applicationAvailability = applicationAvailability;
}
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
if (ReadinessState.READY.equals(this.applicationAvailabilityProvider.getReadinessState())) {
builder.up();
}
else {
builder.outOfService();
}
ReadinessState state = this.applicationAvailability.getReadinessState();
builder.status(ReadinessState.ACCEPTING_TRAFFIC == state ? Status.UP : Status.OUT_OF_SERVICE);
}
}

View File

@@ -20,11 +20,11 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.availability.ApplicationAvailabilityProvider;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.LivenessState;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.when;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
@@ -34,25 +34,25 @@ import static org.mockito.Mockito.mock;
*/
class LivenessProbeHealthIndicatorTests {
private ApplicationAvailabilityProvider stateProvider;
private ApplicationAvailability availability;
private LivenessProbeHealthIndicator healthIndicator;
@BeforeEach
void setUp() {
this.stateProvider = mock(ApplicationAvailabilityProvider.class);
this.healthIndicator = new LivenessProbeHealthIndicator(this.stateProvider);
this.availability = mock(ApplicationAvailability.class);
this.healthIndicator = new LivenessProbeHealthIndicator(this.availability);
}
@Test
void livenessIsLive() {
when(this.stateProvider.getLivenessState()).thenReturn(LivenessState.LIVE);
given(this.availability.getLivenessState()).willReturn(LivenessState.CORRECT);
assertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.UP);
}
@Test
void livenessIsBroken() {
when(this.stateProvider.getLivenessState()).thenReturn(LivenessState.BROKEN);
given(this.availability.getLivenessState()).willReturn(LivenessState.BROKEN);
assertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.DOWN);
}

View File

@@ -20,11 +20,11 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Status;
import org.springframework.boot.availability.ApplicationAvailabilityProvider;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.ReadinessState;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.when;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
@@ -34,25 +34,25 @@ import static org.mockito.Mockito.mock;
*/
class ReadinessProbeHealthIndicatorTests {
private ApplicationAvailabilityProvider stateProvider;
private ApplicationAvailability availability;
private ReadinessProbeHealthIndicator healthIndicator;
@BeforeEach
void setUp() {
this.stateProvider = mock(ApplicationAvailabilityProvider.class);
this.healthIndicator = new ReadinessProbeHealthIndicator(this.stateProvider);
this.availability = mock(ApplicationAvailability.class);
this.healthIndicator = new ReadinessProbeHealthIndicator(this.availability);
}
@Test
void readinessIsReady() {
when(this.stateProvider.getReadinessState()).thenReturn(ReadinessState.READY);
given(this.availability.getReadinessState()).willReturn(ReadinessState.ACCEPTING_TRAFFIC);
assertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.UP);
}
@Test
void readinessIsUnready() {
when(this.stateProvider.getReadinessState()).thenReturn(ReadinessState.UNREADY);
given(this.availability.getReadinessState()).willReturn(ReadinessState.REFUSING_TRAFFIC);
assertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
}