All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mp.guides.health.adoc Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019, 2024 Oracle and/or its affiliates.

    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

        http://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.

///////////////////////////////////////////////////////////////////////////////

= Helidon MP Health Check Guide
:description: Helidon health checks
:keywords: helidon, health checks, health, check
:rootdir: {docdir}/../..

include::{rootdir}/includes/mp.adoc[]

This guide describes how to create a sample MicroProfile (MP) project
that can be used to run some basic examples using both built-in and custom health checks with Helidon MP.

== What You Need

For this 15 minute tutorial, you will need the following:

include::{rootdir}/includes/prerequisites.adoc[tag=prerequisites]

=== Create a Sample MP Project

Generate the project sources using the Helidon MP Maven archetype.
The result is a simple project that can be used for the examples in this guide.

[source,bash,subs="attributes+"]
.Run the Maven archetype:
----
mvn -U archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-mp \
    -DarchetypeVersion={helidon-version} \
    -DgroupId=io.helidon.examples \
    -DartifactId=helidon-quickstart-mp \
    -Dpackage=io.helidon.examples.quickstart.mp
----

=== 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 will demonstrate how to use the built-in health checks.  These examples are all executed
from the root directory of your project (helidon-quickstart-mp).

[source,xml]
.Include dependency for the built-in health checks
include::{rootdir}/mp/health.adoc[tag=built-in-health-checks-depc]

[source,bash]
.Build the application then run it:
----
mvn package
java -jar target/helidon-quickstart-mp.jar
----

[source,bash]
.Verify the health endpoint in a new terminal window:
----
curl http://localhost:8080/health
----

[source,json]
.JSON response:
----
{
  "status": "UP",
  "checks": [
    {
      "name": "deadlock",
      "status": "UP"
    },
    {
      "name": "diskSpace",
      "status": "UP",
      "data": {
        "free": "325.54 GB",
        "freeBytes": 349543358464,
        "percentFree": "69.91%",
        "total": "465.63 GB",
        "totalBytes": 499963174912
      }
    },
    {
      "name": "heapMemory",
      "status": "UP",
      "data": {
        "free": "230.87 MB",
        "freeBytes": 242085696,
        "max": "3.56 GB",
        "maxBytes": 3817865216,
        "percentFree": "98.90%",
        "total": "271.00 MB",
        "totalBytes": 284164096
      }
    }
  ]
}
----

=== Custom Liveness Health Checks

You can create application-specific custom health checks and integrate them with Helidon
using CDI.  The following example shows how to add a custom liveness health check.

[source,java]
.Create a new `GreetLivenessCheck` class with the following content:
----
include::{sourcedir}/mp/guides/HealthSnippets.java[tag=snippet_1, indent=0]
----
<1> Annotation indicating this is a liveness health check.
<2> Annotation indicating there is a single liveness `HealthCheck` object during the lifetime of the application.
<3> Build the HealthCheckResponse with status `UP` and the current time.

[source,bash]
.Build and run the application, then verify the custom liveness health endpoint
----
curl http://localhost:8080/health/live
----

[source,json]
.JSON response:
----
{
  "status": "UP",
  "checks": [
    {
      "name": "LivenessCheck",
      "status": "UP",
      "data": {
        "time": 1566338255331
      }
    }
  ]
}
----

=== Custom Readiness Health Checks

You can add a readiness check to indicate that the application is ready to be used.  In this
example, the server will wait five seconds before it becomes ready.

[source,java]
.Create a new `GreetReadinessCheck` class with the following content:
----
include::{sourcedir}/mp/guides/HealthSnippets.java[tag=snippet_2, indent=0]
----
<1> Annotation indicating that this is a readiness health check.
<2> Build the `HealthCheckResponse` with status `UP` after five seconds, else `DOWN`.
<3> Record the time at startup.


[source,bash]
.Build and run the application.  Issue the curl command with -v within five seconds, and you will see that the application is not ready:
----
curl -v  http://localhost:8080/health/ready
----

[source, listing]
.HTTP response status
----
< HTTP/1.1 503 Service Unavailable // <1>
----
<1> The HTTP status is `503` since the application is not ready.

[source,json]
.Response body
----
{
  "status": "DOWN",
  "checks": [
    {
      "name": "ReadinessCheck",
      "status": "DOWN",
      "data": {
        "time": 1566399775700
      }
    }
  ]
}
----

[source,bash]
.After five seconds you will see the application is ready:
----
curl -v http://localhost:8080/health/ready
----

[source,listing]
.HTTP response status
----
< HTTP/1.1 200 OK // <1>
----
<1> The HTTP status is `200` indicating that the application is ready.

[source,json]
.Response body
----
{
  "status": "UP",
  "checks": [
    {
      "name": "ReadinessCheck",
      "status": "UP",
      "data": {
        "time": 1566399775700
      }
    }
  ]
}
----

=== Custom Startup Health Checks

You can add a startup check to indicate if the application is initialized to the point that the other health checks make sense.
In this example, the server will wait eight seconds before it declares itself started.

[source,java]
.Create a new `GreetStartedCheck` class with the following content:
----
include::{sourcedir}/mp/guides/HealthSnippets.java[tag=snippet_3, indent=0]
----
<1> Annotation indicating that this is a startup health check.
<2> Build the `HealthCheckResponse` with status `UP` after eight seconds, else `DOWN`.
<3> Record the time at startup of Helidon; the application will declare itself as started eight seconds later.


[source,bash]
.Build and run the application.  Issue the curl command with -v within five seconds, and you will see that the application has not yet started:
----
curl -v  http://localhost:8080/health/started
----

[source,listing]
.HTTP response status
----
< HTTP/1.1 503 Service Unavailable // <1>
----
<1> The HTTP status is `503` since the application has not started.

[source,json]
.Response body
----
{
  "status": "DOWN",
  "checks": [
    {
      "name": "StartedCheck",
      "status": "DOWN",
      "data": {
        "time": 1566399775700
      }
    }
  ]
}
----

[source,bash]
.After eight seconds you will see the application has started:
----
curl -v http://localhost:8080/health/started
----

[source,listing]
.HTTP response status
----
< HTTP/1.1 200 OK // <1>
----
<1> The HTTP status is `200` indicating that the application is started.

[source,json]
.Response body
----
{
  "status": "UP",
  "checks": [
    {
      "name": "StartedCheck",
      "status": "UP",
      "data": {
        "time": 1566399775700
      }
    }
  ]
}
----

When using the health check URLs, you can get the following health check data:

* liveness only - http://localhost:8080/health/live
* readiness only -  http://localhost:8080/health/ready
* startup checks only - http://localhost:8080/health/started
* all health check data -  http://localhost:8080/health

[source,bash]
.Get all the health check data, including custom data:
----
curl http://localhost:8080/health
----

[source,json]
.JSON response:
----
{
  "status": "UP",
  "checks": [
    {
      "name": "LivenessCheck",
      "status": "UP",
      "data": {
        "time": 1566403431536
      }
    },
    {
      "name": "ReadinessCheck",
      "status": "UP",
      "data": {
        "time": 1566403280639
      }
    },
    {
      "name": "StartedCheck",
      "status": "UP",
      "data": {
        "time": 1566403280639
      }
    },
    {
      "name": "deadlock",
      "state": "UP",
      "status": "UP"
    },
    {
      "name": "diskSpace",
      "state": "UP",
      "status": "UP",
      "data": {
        "free": "325.50 GB",
        "freeBytes": 349500698624,
        "percentFree": "69.91%",
        "total": "465.63 GB",
        "totalBytes": 499963174912
      }
    },
    {
      "name": "heapMemory",
      "state": "UP",
      "status": "UP",
      "data": {
        "free": "231.01 MB",
        "freeBytes": 242235928,
        "max": "3.56 GB",
        "maxBytes": 3817865216,
        "percentFree": "98.79%",
        "total": "275.00 MB",
        "totalBytes": 288358400
      }
    }
  ]
}
----


=== Custom Health Root Path and Port

You can specify a custom port and root context for the root health endpoint path.
However, you cannot use different ports, such as http://localhost:8080/myhealth and http://localhost:8081/myhealth/live.
Likewise, you cannot use different paths, such as http://localhost:8080/health and http://localhost:8080/probe/live.

The example below will change the root path.

[source,yaml]
.Create a file named `application.yaml` in the `resources` directory with the following contents:
----
health:
  endpoint: "/myhealth" # <1>
----
<1> The `endpoint` settings specifies the root path for the health endpoint.

[source,bash]
.Build and run the application, then verify that the health endpoint is using the new `/myhealth` root:
----
curl http://localhost:8080/myhealth
curl http://localhost:8080/myhealth/live
curl http://localhost:8080/myhealth/ready
curl http://localhost:8080/myhealth/started
----

The following example will change the root path and the health port.

[source,yaml]
.Update application.yaml to use a different port and root path for the health endpoint:
----
server:
  port: 8080 # <1>
  sockets:
    - name: "admin" # <2>
      port: 8081 # <3>
  features:
    observe:
      sockets: "admin" # <4>
health:
  endpoint: "/myhealth" # <5>
----
<1> The default port for the application.
<2> The name of the new socket, it can be any name, this example uses `admin`.
<3> The port for the `admin` socket.
<4> The health endpoint, as part of Helidon's observability support, uses the socket `admin`.


[source,bash]
.Build and run the application, then verify the health endpoint using port `8081` and `/myhealth`:
----
curl http://localhost:8081/myhealth
curl http://localhost:8081/myhealth/live
curl http://localhost:8081/myhealth/ready
curl http://localhost:8081/myhealth/started
----

=== Using Liveness, Readiness, and Startup Health Checks with Kubernetes

The following example shows how to integrate the Helidon health check API with an application that implements
health endpoints for the Kubernetes liveness, readiness, and startup probes.

*Delete the contents of `application.yaml` so that the default health endpoint path and port are used.*

[source,bash]
.Rebuild and start the application, then verify the health endpoint:
----
curl http://localhost:8080/health
----

[source,bash]
.Stop the application and build the docker image:
----
docker build -t helidon-quickstart-mp .
----

[source,yaml]
.Create the Kubernetes YAML specification, named `health.yaml`, with the following content:
----
kind: Service
apiVersion: v1
metadata:
  name: helidon-health # <1>
  labels:
    app: helidon-health
spec:
  type: NodePort
  selector:
    app: helidon-health
  ports:
    - port: 8080
      targetPort: 8080
      name: http
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: helidon-health # <2>
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helidon-health
  template:
    metadata:
      labels:
        app: helidon-health
        version: v1
    spec:
      containers:
        - name: helidon-health
          image: helidon-quickstart-mp
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
          livenessProbe:
            httpGet:
              path: /health/live # <3>
              port: 8080
            initialDelaySeconds: 5 # <4>
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/ready # <5>
              port: 8080
            initialDelaySeconds: 5 # <6>
            periodSeconds: 2
            timeoutSeconds: 3
          startupProbe:
            httpGet:
              path: /health/started # <7>
              port: 8080
            initialDelaySeconds: 8 # <8>
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
---
----
<1> A service of type `NodePort` that serves the default routes on port `8080`.
<2> A deployment with one replica of a pod.
<3> The HTTP endpoint for the liveness probe.
<4> The liveness probe configuration.
<5> The HTTP endpoint for the readiness probe.
<6> The readiness probe configuration.
<7> The HTTP endpoint for the startup probe.
<8> The startup probe configuration.


[source,bash]
.Create and deploy the application into Kubernetes:
----
kubectl apply -f ./health.yaml
----

[source,bash]
.Get the service information:
----
kubectl get service/helidon-health
----

[source,bash]
----
NAME             TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
helidon-health   NodePort   10.107.226.62           8080:30116/TCP   4s # <1>
----
<1> A service of type `NodePort` that serves the default routes on port `30116`.

[source,bash]
.Verify the health endpoints using port '30116', your port may be different. The JSON response will be the same as your previous test:
----
curl http://localhost:30116/health
----

[source,bash]
.Delete the application, cleaning up Kubernetes resources:
----
kubectl delete -f ./health.yaml
----

=== Summary
This guide demonstrated how to use health checks in a Helidon MP application as follows:

* Access the default health checks
* Create and use custom readiness, liveness, and startup checks
* Customize the health check root path and port
* Integrate Helidon health check API with Kubernetes

Refer to the following references for additional information:

* link:{microprofile-health-spec-url}[MicroProfile health check specification]
* link:{microprofile-health-javadoc-url}[MicroProfile health check Javadoc]
* link:{javadoc-base-url}/index.html?overview-summary.html[Helidon Javadoc]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy