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.14.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:
-
start your Quarkus application with
mvn compile quarkus:dev
-
access the
http://localhost:8080/health
endpoint using your browser orcurl http://localhost:8080/health
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 thequarkus-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>