Health
This guide describes how to create a sample Helidon SE project that can be used to run some basic examples using both built-in and custom health checks.
What You Need
For this 15 minute tutorial, you will need the following:
| Requirement | Description |
|---|---|
| Java 21 (Open JDK 21) | Helidon requires Java 21+ (25+ recommended). |
| Maven 3.8+ | Helidon requires Maven 3.8+. |
| Docker 18.09+ | If you want to build and run Docker containers. |
| Kubectl 1.16.5+ | If you want to deploy to Kubernetes, you need kubectl and a Kubernetes cluster. |
Prerequisite product versions for Helidon 4.4.0-SNAPSHOT
Verify Prerequisites:
java -version
mvn --version
docker --version
kubectl version
Setting JAVA_HOME:
# On Mac
export JAVA_HOME=`/usr/libexec/java_home -v 21`
# On Linux
# Use the appropriate path to your JDK
export JAVA_HOME=/usr/lib/jvm/jdk-21
Create a Sample SE Project
Generate the project sources using the Helidon SE Maven archetype. The result is a simple project that can be used for the examples in this guide.
Run the Maven archetype:
mvn -U archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=io.helidon.archetypes \
-DarchetypeArtifactId=helidon-quickstart-se \
-DarchetypeVersion=4.4.0-SNAPSHOT \
-DgroupId=io.helidon.examples \
-DartifactId=helidon-quickstart-se \
-Dpackage=io.helidon.examples.quickstart.se
Using the Built-In Health Checks
Helidon has a set of built-in health checks:
- deadlock detection
- available disk space
- available heap memory
The following example shows how to use the built-in health checks. These examples are all executed from the root directory of your project (helidon-quickstart-se).
Notice that the pom.xml file in the generated project already contains
dependencies for Helidon’s health component and for the built-in health checks.
Generated dependencies related to health:
<dependencies>
<dependency>
<groupId>io.helidon.webserver.observe</groupId>
<artifactId>helidon-webserver-observe-health</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.health</groupId>
<artifactId>helidon-health-checks</artifactId>
</dependency>
</dependencies>
Handling health checks is part of Helidon’s observability support. By default, when you add the dependency for the built-in health checks, Helidon automatically registers the built-in checks.
Build and run the project:
mvn clean package
java -jar target/helidon-quickstart-se.jar
In another window, access the application’s health endpoint.
Access the health endpoint:
curl -v http://localhost:8080/observe/health
The verbose curl output reports the HTTP status:
< HTTP/1.1 204 No Content
The successful status means all health checks reported UP.
To see the details about each health check, add the following features
configuration fragment in the server section of the application.yaml. Make
sure the features key is at the same level as port and host that are
already in the file.
Configuration fragment to include details in the health output (nested under server):
Press ^C to stop the running server, rebuild it, and rerun it.
Stop, rebuild, and rerun the server:
^C
mvn clean package
java -jar target/helidon-quickstart-se.jar
In the other window access the health endpoint again.
Access the health endpoint:
curl -v http://localhost:8080/observe/health
This time the curl output shows not only the HTTP status as 200 instead of
204 because the response now contains data but also the detailed output for all
health checks.
Health check details:
Adding Custom Health Checks
You can add your own custom health checks. These typically assess the conditions in and around your application and report whether the service should be considered started, live, and/or ready.
The following trivial but illustrative example adds a custom start-up check that
reports DOWN until the server has been running for eight seconds and reports
UP thereafter. Note the two main steps in the example code:
- Create an explicit instance of
ObserveFeaturewhich contains a customHealthObserverwith the custom check. - Add that
ObserveFeatureinstance to theWebServerConfig.Builderas a feature.
Updated Main#main, augmenting the creation of WebServer instance with a custom health check:
Note that the health check type and name are fixed, whereas the health check recomputes the value of the response every time Helidon queries it.
Stop, rebuild, and rerun the application:
^C
mvn package
java -jar target/helidon-quickstart-se.jar
Access the health endpoint quickly
curl -v http://localhost:8080/observe/health
If you access the health endpoint before the server has been up for eight
seconds, curl reports the response status as 503 Service Unavailable and
displays output similar to the following:
Health response shortly after server restart (partial):
{
"status": "DOWN",
"checks": [
{
"name": "warmedUp",
"status": "DOWN",
"data": {
"time": 1702068978353
}
}
]
}
The built-in health checks (not shown in the example output) all report UP but
the new custom start-up health check reports DOWN because the server has been
up only a short time.
Access the health endpoint again, after the server has been up at least eight seconds.
Access the health endpoint again after 8 seconds
curl -v http://localhost:8080/observe/health
This time, curl reports 200 OK for the response status and displays
different output for the custom health check.
Health response after the server has been running a while (partial):
{
"status": "UP",
"checks": [
{
"name": "warmedUp",
"status": "UP",
"data": {
"time": 1702069379717
}
}
]
}
The example code includes the built-in health checks in Helidon’s overall health
assessment of the application. To exclude them invoke the
HealthObserver.Builder useSystemServices method (for example, just after
invoking details on the builder).
Disable all built-in health checks:
HealthObserver.builder()
.useSystemServices(false)
.build();
Alternatively, you could instead remove the dependency on the
helidon-health-checks component from the pom.xml file.
Accessing Specific Health Check Types
You can choose which category of health check to retrieve when you access the health endpoint by adding the health check type as an additional part of the resource path:
- liveness only - http://localhost:8080/observe/health/live
- readiness only - http://localhost:8080/observe/health/ready
- startup only - http://localhost:8080/observe/health/started
- all - http://localhost:8080/observe/health
Get only start-up health checks:
curl http://localhost:8080/observe/started
{
"status": "UP",
"checks": [
{
"name": "warmedUp",
"status": "UP",
"data": {
"time": 1702069835172
}
}
]
}
Applying Configuration to a Custom Health Observer: Customizing the URL path
Earlier examples showed how to add custom health checks by building a custom
HealthObserver in which the code set up the behavior of the health subsystem
explicitly. Recall that the example code invoked the HealthObserver.Builderdetails method to turn on detailed output.
Once it creates a custom health observer, your code has full responsibility for determining the observer’s behavior; Helidon does not automatically apply configuration to a custom observer. But your code can easily do so.
The next example customizes the URL path for the health endpoint, first explicitly in the code and then via configuration.
Customizing the endpoint path in the code
Customize the URL path for health checks by invoking the endpoint method on
the HealthObserver.Builder.
Set a custom endpoint path:
Build and run the application, then verify that the health check endpoint responds at /myhealth:
curl http://localhost:8080/myhealth
Earlier you added health config to the application.yaml config file to turn on
detailed output. If you want to run an experiment, change that details setting
in the config file to false and stop, rebuild, and rerun the application. Now
access the health endpoint (at /myhealth, remember). The output remains
detailed because your code which has full responsibility for determining the
custom health observer’s behavior does not apply configuration to the custom
observer’s builder.
Adding configuration to a custom observer
In addition to preparing the health observer builder with hard-coded settings, your code can also apply configuration for health. This allows someone who deploys your application to control the behavior of the health subsystem using configuration without requiring source code changes to your application.
The generated Main class in the application already creates a Config object
for the top-level config node. Using the following code to create the observe
feature also applies any health-related configuration settings to the custom
health observer. Notice the added line just before the HealthObserver.Buildbuild() invocation near the end of the example code.
Apply health configuration to your custom health observer:
Your code decides what config key to use for retrieving the configuration.
Recall earlier, before adding custom health checks, you added a config section
for health to set details to true--at
server.features.observe.observers.health. Helidon used that configuration to
set up the health observer it created automatically. To be consistent for
anyone preparing the configuration file, it’s a good idea for your application
code as it prepares a custom HealthObserver--to look in the same place
Helidon does for health config.
Order is important. Here, the code first sets details to true explicitly and
later applies configuration. If your end user sets details in the
server.features.observe.observers.health config to false, that setting
overrides the hard-coded true setting in the code because of where in the
code you apply the configuration. Try changing the details value to false
in the config file and then stop, rebuild, and rerun the application. Access the
health endpoint and notice that the output is no longer detailed.
In general, most applications should apply settings from config after assigning any settings in the code so users have the final say, but there might be exceptions in your particular case.
Using Liveness, Readiness, and Startup Health Checks with Kubernetes
The following example shows how to integrate the Helidon health API in an application that implements health endpoints for the Kubernetes liveness, readiness, and startup probes.
Add a readyTime variable to the Main class:
private static AtomicLong readyTime = new AtomicLong(0);
Change the HealthObserver builder in the Main#main method to use new built-in liveness checks and custom liveness, readiness, and startup checks:
Build and run the application, then verify the liveness, readiness, and started endpoints:
curl http://localhost:8080/health/live
curl http://localhost:8080/health/ready
curl http://localhost:8080/health/started
Stop the application and build the docker image:
docker build -t helidon-quickstart-se .
Create the Kubernetes YAML specification, named health.yaml, with the
following content:
Create and deploy the application into Kubernetes:
kubectl apply -f ./health.yaml
Get the service information:
kubectl get service/helidon-health
Verify the health endpoints using port '30116', your port may be different:
curl http://localhost:30116/health
Delete the application, cleaning up Kubernetes resources:
kubectl delete -f ./health.yaml
Summary
This guide demonstrates how to use health checks in a Helidon SE application as follows:
- Access the default health checks
- Create and use custom readiness, liveness, and startup checks
- Customize the health check root path
- Integrate Helidon health check with Kubernetes
Refer to the following reference for additional information: