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

    Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

    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.

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

= Health Checks
:description: Helidon health checks
:keywords: helidon, health-checks, health, check

This document describes the health check API available with Helidon SE.

== About health checks

It’s a good practice to monitor your microservice’s health, to ensure that it is
 available and performs correctly.

Applications implement health checks to expose health status that is collected
 at regular intervals by external tooling, such as orchestrators like
 Kubernetes. The orchestrator may then take action, such as restarting your
 application if the health check fails.

A typical health check combines the statuses of all the dependencies that
 affect availability and the ability to perform correctly:

* network latency
* storage
* database
* other services used by your application

=== Prerequisites

Declare the following dependency in your project:

[source,xml]
----
<dependency>
    <groupId>io.helidon.health</groupId>
    <artifactId>helidon-health</artifactId>
</dependency>
----

[source,xml]
.Optional dependency to use built-in health checks:
----
<dependency>
    <groupId>io.helidon.health</groupId>
    <artifactId>helidon-health-checks</artifactId>
</dependency>
----

== API overview

[cols="4,6"]
.Health check API classes
|=======
| `org.eclipse.microprofile.health.HealthCheck`
| Java functional interface representing the logic of a single health check

| `org.eclipse.microprofile.health.HealthCheckResponse`
| Result of a health check invocation that contains a state and a description.

| `org.eclipse.microprofile.health.HealthCheckResponseBuilder`
| Builder class to create `HealthCheckResponse` instances

| `io.helidon.health.HealthSupport`
| WebServer service that exposes `/health` and invokes the registered health
 checks

| `io.helidon.health.HealthSupport.Builder`
| Builder class to create `HealthSupport` instances
|=======

A health check is a Java functional interface that returns a
 `HealthCheckResponse` object. You can choose to implement a health check
 inline with a lambda expression or you can reference a method with the double
 colon operator `::`.

[source,java]
.Health check with a lambda expression:
----
HealthCheck hc = () -> HealthCheckResponse
        .named("exampleHealthCheck")
        .up()
        .build();
----

[source,java]
.Health check with method reference:
----
HealthCheckResponse exampleHealthCheck(){
    return HealthCheckResponse
        .named("exampleHealthCheck")
        .up()
        .build();
}
HealthCheck hc = this::exampleHealthCheck;
----

`HealthSupport` is a WebServer service that contains a collection of
 registered `HealthCheck` instances. When queried, it invokes the registered
 health check and returns a response with a status code representing the overall
 state of the application.

[cols="1,5",role="flex, sm7"]
.Health status codes
|=======
| `200` | The application is healthy.
| `503` | The application is not healthy.
| `500` | An error occurred while reporting the health.
|=======

The HTTP response also contains a JSON payload that describes the statuses for
 all health checks.

[source,java]
.Create the health support service:
----
HealthSupport health = HealthSupport.builder()
    .addLiveness(hc)
    .build();
----

NOTE: Health check requires the `JSON-P` support to be enabled. See the example
 below.

=== Example

[source,java]
.Register a custom health check:
----
HealthSupport health = HealthSupport.builder()
    .addLiveness(() -> HealthCheckResponse.named("exampleHealthCheck")
                 .up()
                 .withData("time", System.currentTimeMillis())
                 .build()) // <1>
    .build();

Routing.builder()
        .register(JsonSupport.create()) // <2>
        .register(health) // <3>
        .build();
----
<1> Add a custom health check. This example returns `UP` and current time.
<2> Enable support for `JSON`.
<3> Register health support with web server routing (adds the `/health`
 endpoint).

TIP: Balance collecting a lot of information with the need to avoid overloading
 the application and overwhelming users.

[source,json]
.JSON response:
----
{
    "outcome": "UP",
    "checks": [
        {
            "name": "exampleHealthCheck",
            "state": "UP",
            "data": {
                "time": 1546958376613
            }
        }
    ]
}
----

=== Built-in health-checks

A set of built-in health checks can be optionally enabled to report various
 health check statuses that are commonly used:

* deadlock detection
* available disk space
* available heap memory

[source,java]
----
HealthSupport health = HealthSupport.builder()
    .addLiveness(HealthChecks.healthChecks()) // <1>
    .build();

Routing.builder()
        .register(JsonSupport.create()) // <2>
        .register(health) // <3>
        .build();
----
<1> Add built-in health checks (requires the `helidon-health-checks`
 dependency).
<2> Register the `JSON-P` support in the WebServer routing.
<3> Register the created health support with web server routing (adds the 
`/health` endpoint).

[source,json]
.JSON response.
----
{
    "outcome": "UP",
    "checks": [
        {
            "name": "deadlock",
            "state": "UP"
        },
        {
            "name": "diskSpace",
            "state": "UP",
            "data": {
                "free": "211.00 GB",
                "freeBytes": 226563444736,
                "percentFree": "45.31%",
                "total": "465.72 GB",
                "totalBytes": 500068036608
            }
        },
        {
            "name": "heapMemory",
            "state": "UP",
            "data": {
                "free": "215.15 MB",
                "freeBytes": 225600496,
                "max": "3.56 GB",
                "maxBytes": 3817865216,
                "percentFree": "99.17%",
                "total": "245.50 MB",
                "totalBytes": 257425408
            }
        }
    ]
}
----
