Health Guide

This guide demonstrates how your Quarkus application can utilize the MicroProfile Health specification through the SmallRye Health extension.

MicroProfile Health allows applications to provide information about their state to external viewers which is typically useful in cloud environments where automated processes must be able to determine whether the application should be discarded or restarted.

Prerequisites

To complete this guide, you need:

  • less than 15 minutes

  • an IDE

  • JDK 1.8+ installed with JAVA_HOME configured appropriately

  • Apache Maven 3.5.3+

Architecture

In this guide, we build a simple REST application that exposes MicroProfile Health functionalities at the /health endpoint according to the specification. It will also provide several other REST endpoints to allow us to dynamically change the healthness of our Quarkus application.

Solution

We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.

Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git, or download an archive.

The solution is located in the microprofile-health directory.

Creating the Maven Project

First, we need a new project. Create a new project with the following command:

mvn io.quarkus:quarkus-maven-plugin:0.15.0:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=microprofile-health \
    -Dextensions="smallrye-health"

This command generates a Maven project, importing the smallrye-health extension which is an implementation of the MicroProfile Health specification used in Quarkus.

Running the health check

Importing the smallrye-health extension directly exposes a single REST endpoint at the /health endpoint that can be used to run the health check procedures:

The health REST enpoint returns a simple JSON object with two fields:

  • outcome — the overall result of all the health check procedures

  • checks — an array of individual checks

The general outcome of the health check is computed as a logical AND of all the declared health check procedures. The checks array is empty as we have not specified any health check procedure yet so let’s define some.

Creating your first health check

In this section we create our first simple health check procedure.

Create the org.acme.health.SimpleHealthCheck class:

package org.acme.health;

import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

import javax.enterprise.context.ApplicationScoped;

@Health
@ApplicationScoped
public class SimpleHealthCheck implements HealthCheck {

    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.named("Simple health check").up().build();
    }
}

As you can see health check procedures are defined as implementations of the HealthCheck interface which are defined as CDI beans with the @Health qualifier. HealthCheck is a functional interface whose single method call returns a HealthCheckResponse object which can be easily constructed by the fluent builder API shown in the example.

As we have started our Quarkus application in dev mode simply repeat the request to http://localhost:8080/health by refreshing your browser window or by using curl http://localhost:8080/health. The new health check procedure is now present in the checks array.

Congratulations! You’ve created your first Quarkus health check procedure. Let’s continue by exploring what else can be done with the MicroProfile Health specification.

Adding user specific data to the health check response

In previous section we saw how to create a simple health check with only the minimal attributes, namely, the health check name and its state (UP or DOWN). However, the MicroProfile specification also provides a way for the applications to supply arbitrary data in the form of key value pairs sent to the consuming end. This can be done by using the withData(key, value) method of the health check response builder API.

Let’s create our second health check procedure org.acme.health.DataHealthCheck:

package org.acme.health;

import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

import javax.enterprise.context.ApplicationScoped;

@Health
@ApplicationScoped
public class DataHealthCheck implements HealthCheck {

    @Override
    public HealthCheckResponse call() {
        return HealthCheckResponse.named("Health check with data")
                .up()
                .withData("foo", "fooValue")
                .withData("bar", "barValue")
                .build();
    }
}

If you rerun the health check procedure again by accessing the /health endpoint you can see that the new health check Health check with data is present in the checks array. This check contains a new attribute called data which is a JSON object consisting of the properties we have defined in our health check procedure.

Negative health check procedure

In this section we create another health check procedure which simulates a connection to an external service provider such as a database. For simplicity reasons, we only determine whether the database is accessible or not by a configuration property.

Create org.acme.health.DatabaseConnectionHealthCheck class:

package org.acme.health;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.HealthCheckResponseBuilder;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

@Health
@ApplicationScoped
public class DatabaseConnectionHealthCheck implements HealthCheck {

    @ConfigProperty(name = "database.up", defaultValue = "false")
    private boolean databaseUp;

    @Override
    public HealthCheckResponse call() {

        HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named("Database connection health check");

        try {
            simulateDatabaseConnectionVerification();
            responseBuilder.up();
        } catch (IllegalStateException e) {
            // cannot access the database
            responseBuilder.down()
                    .withData("error", e.getMessage());
        }

        return responseBuilder.build();
    }

    private void simulateDatabaseConnectionVerification() {
        if (!databaseUp) {
            throw new IllegalStateException("Cannot contact database");
        }
    }
}

If you now rerun the health check the overall outcome should be DOWN and you should see in the checks array the newly added Database connection health check which is down and the error message explaining why it failed.

As we shouldn’t leave this application with a health check in DOWN state and because we are running Quarkus dev mode you can add database.up=true in src/main/resources/application.properties and rerun the health check again — it should be up again.

Conclusion

MicroProfile Health provides a way for your application to distribute information about its healthness state to state whether or not it is able to function properly.

All that is needed to enable the MicroProfile Health features in Quarkus is:

  • adding the smallrye-health Quarkus extension to your project using the quarkus-maven-plugin:

    mvn quarkus:add-extension -Dextensions="smallrye-health"
  • or simply adding the following Maven dependency:

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-health</artifactId>
    </dependency>