Polish Liveness and Readiness support

This commit moves the core Liveness and Readiness support to its own
`availability` package. We've made this a core concept independent of
Kubernetes.

Spring Boot now produces `LivenessStateChanged` and
`ReadinessStateChanged` events as part of the typical application
lifecycle.

Liveness and Readiness Probes (`HealthIndicator` components and health
groups) are still configured only when deployed on Kubernetes.

This commit also improves the documentation around Probes best practices
and container lifecycle considerations.

See gh-19593
This commit is contained in:
Brian Clozel
2020-03-20 23:49:28 +01:00
parent 3edc1c3a7d
commit ffdf9a422f
30 changed files with 521 additions and 354 deletions

View File

@@ -191,6 +191,90 @@ NOTE: There are some restrictions when creating an `ApplicationContext` hierarch
For example, Web components *must* be contained within the child context, and the same `Environment` is used for both parent and child contexts.
See the {spring-boot-module-api}/builder/SpringApplicationBuilder.html[`SpringApplicationBuilder` Javadoc] for full details.
[[boot-features-application-availability-state]]
== Application Availability State
When deployed on plaftorms, applications can provide information about their availability to the platform using infrastructure like https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/[Kubernetes Probes].
Spring Boot manages this application state with the `ApplicationAvailabilityProvider` and makes it available to application components and the platform itself.
[[boot-features-application-availability-liveness]]
=== Liveness State
The "Liveness" state of an application tells whether its internal state allows it to work correctly, or recover by itself if it's currently failing.
An invalid "Liveness" state means that the application is in a broken state and cannot recover from it; the infrastructure should then restart the application to mitigate that problem.
NOTE: In general, the "Liveness" state should not be based on external checks, such as <<production-ready-features.adoc#production-ready-health, Health checks>>.
If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform.
The internal state of Spring Boot applications is mostly represented by the Spring application context.
If the application context has started successfully, Spring Boot assumes that the application is in a valid state.
An application is considered live as soon as the context has been refreshed, see <<boot-features-application-events-and-listeners, Spring Boot application lifecycle and related Application Events>>.
[[boot-features-application-availability-readiness]]
=== Readiness State
The "Readiness" state of an application tells whether the application is ready to handle traffic.
A failing "Readiness" state tells the platform that it should not route traffic to the application for now.
This typically happens during startup, while `CommandLineRunner` and `ApplicationRunner` components are being processed, or at any time if the application decides that it's too busy for additional traffic.
An application is considered ready as soon as application and command-line runners have been called, see <<boot-features-application-events-and-listeners, Spring Boot application lifecycle and related Application Events>>.
TIP: Tasks expected to run during startup should be executed by `CommandLineRunner` and `ApplicationRunner` components instead of using Spring component lifecycle callbacks such as `@PostConstruct`.
[[boot-features-managing-application-availability]]
=== Managing the Application Availability State
Application components can retrieve the current availability state at any time, by injecting the `ApplicationAvailabilityProvider` and calling methods on it.
More often, applications will want to listen to state updates or update the state of the application.
For example, we can export the "Readiness" state of the application to a file so that a Kubernetes "exec Probe" can look at this file:
[source,java,indent=0]
----
@Component
public class ReadinessStateExporter implements ApplicationListener<LivenessStateChangedEvent> {
@Override
public void onApplicationEvent(LivenessStateChangedEvent event) {
switch (event.getReadinessState().getStatus()) {
case READY:
// create file /tmp/healthy
break;
case UNREADY:
// remove file /tmp/healthy
break;
}
}
}
----
We can also update the state of the application, when the application breaks and cannot recover:
[source,java,indent=0]
----
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBrokenException ex) {
this.eventPublisher.publishEvent(LivenessStateChangedEvent.broken(ex));
}
}
}
----
Spring Boot provides <<production-ready-features.adoc#production-ready-kubernetes-probes,Kubernetes HTTP probes for "Liveness" and "Readiness" with Actuator Health Endpoints>>.
You can get more guidance about <<deployment.adoc#cloud-deployment-kubernetes,deploying Spring Boot applications on Kubernetes in the dedicated section>>.
[[boot-features-application-events-and-listeners]]
@@ -218,8 +302,9 @@ Application events are sent in the following order, as your application runs:
. An `ApplicationContextInitializedEvent` is sent when the `ApplicationContext` is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded.
. An `ApplicationPreparedEvent` is sent just before the refresh is started but after bean definitions have been loaded.
. An `ApplicationStartedEvent` is sent after the context has been refreshed but before any application and command-line runners have been called.
. An `LivenessStateChangedEvent` is sent right after to indicate that the application is considered as live.
. An `ApplicationReadyEvent` is sent after any application and command-line runners have been called.
It indicates that the application is ready to service requests.
. An `ReadinessStateChangedEvent` is sent right after to indicate that the application is ready to service requests.
. An `ApplicationFailedEvent` is sent if there is an exception on startup.
The above list only includes ``SpringApplicationEvent``s that are tied to a `SpringApplication`.
@@ -6013,91 +6098,6 @@ For instance, it is possible to customize the name of the table for the JDBC sto
For setting the timeout of the session you can use the configprop:spring.session.timeout[] property.
If that property is not set, the auto-configuration falls back to the value of configprop:server.servlet.session.timeout[].
[[boot-features-kubernetes-application-state]]
== Kubernetes Application State
When deployed on Kubernetes, applications can provide information about their state to the platform using https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/[Kubernetes Probes].
Spring Boot manages this application state with the `ApplicationStateProvider` and makes it available to application components and the cloud platform itself.
This feature is only enabled when the application is running on Kubernetes.
TIP: The cloud platform detection relies on platform-specific environment variables, but you can override this detection with the configprop:spring.main.cloud-platform[] configuration property.
[[boot-features-kubernetes-liveness-state]]
=== Liveness State
The "Liveness" state of an application tells whether its internal state allows it to work correctly, or recover by itself if it's currently failing.
An invalid "Liveness" state means that the application is in a broken state and cannot recover from it; the infrastructure should then restart the application to mitigate that problem.
NOTE: In general, the "Liveness" state should not be based external checks, such as <<production-ready-features.adoc#production-ready-health, Health checks>>.
If it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform.
The internal state of Spring Boot applications is mostly represented by the Spring application context.
If the application context has started successfully, Spring Boot assumes that the application is in a valid state.
An application is considered live as soon as the `ApplicationStartedEvent` has been published, see <<boot-features-application-events-and-listeners, Spring Boot application lifecycle and related Application Events>>.
[[boot-features-kubernetes-readiness-state]]
=== Readiness State
The "Readiness" state of an application tells whether the application is ready to handle traffic.
A failing "Readiness" state tells Kubernetes that it should not route traffic to the application for now.
This typically happens during startup, while `CommandLineRunner` and `ApplicationRunner` components are being processed, or at any time if the application decides that it's too busy for additional traffic.
An application is considered ready as soon as the `ApplicationReadyEvent` has been published, see <<boot-features-application-events-and-listeners, Spring Boot application lifecycle and related Application Events>>.
TIP: Tasks expected to run during startup should be executed by `CommandLineRunner` and `ApplicationRunner` components instead of using Spring component lifecycle callbacks such as `@PostConstruct`.
[[boot-features-kubernetes-managing-state]]
=== Managing Kubernetes Application State
Application components can retrieve the current application state at any time, by injecting the `ApplicationStateProvider` and calling methods on it.
More often, applications will want to listen to state updates or update the state of the application.
For example, we can export the "Readiness" state of the application to a file so that a Kubernetes "exec Probe" can look at this file:
[source,java,indent=0]
----
@Component
public class LivenessStateExporter implements ApplicationListener<LivenessStateChangedEvent> {
@Override
public void onApplicationEvent(LivenessStateChangedEvent event) {
switch (event.getLivenessState().getStatus()) {
case LIVE:
// create file /tmp/healthy
break;
case BROKEN:
// remove file /tmp/healthy
break;
}
}
}
----
We can also update the state of the application, when the application breaks and cannot recover:
[source,java,indent=0]
----
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBroken ex) {
this.eventPublisher.publishEvent(LivenessStateChangedEvent.broken(ex));
}
}
}
----
Spring Boot provides <<production-ready-features.adoc#production-ready-kubernetes-probes,Kubernetes HTTP probes for "Liveness" and "Readiness" with Actuator Health Endpoints>>.
You can get more guidance about <<deployment.adoc#cloud-deployment-kubernetes,deploying Spring Boot applications on Kubernetes in the dedicated section>>.
[[boot-features-jmx]]
== Monitoring and Management over JMX