October 13, 2019

Eclipse Microprofile Health with Java EE 8 and JBoss EAP 7.2

In my previous blogs we have layed out a maven project for Eclipse Microprofile and tested Eclipse Microprofile Configuration.

In this blog we will test Eclipse Microprofile Health with JBoss EAP 7.2. First all Eclipse Microprofile in JBoss EAP 7.2 are "Technology Previews only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs)". [https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.2/html-single/configuration_guide/index#microprofile_health_check]

"By default, the MicroProfile Health SmallRye subsystem only examines if the server is running."

You can invoke/call Health in two ways. Through CLI or HTTP.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
    "outcome" => "success",
    "result" => {
        "outcome" => "UP",
        "checks" => []
    }
}

The HTTP endpoint is only exposed through the management interface. "The default address for the /health endpoint, accessible from the management interfaces, is http://127.0.0.1:9990/health."

And also there is not much of configuration you can do.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:read-resource-description(recursive=true, inherited=true)
{
    "outcome" => "success",
    "result" => {
        "description" => "WildFly Extension for Eclipse MicroProfile Health With SmallRye",
        "capabilities" => [
            {
                "name" => "org.wildfly.extension.microprofile.health.smallrye",
                "dynamic" => false
            },
            {
                "name" => "org.wildlfy.microprofile.health.reporter",
                "dynamic" => false
            }
        ],
        "attributes" => {"security-enabled" => {
            "type" => BOOLEAN,
            "description" => "True if authentication is required to access the HTTP endpoint on the HTTP management interface.",
            "expressions-allowed" => true,
            "required" => false,
            "nillable" => true,
            "default" => true,
            "access-type" => "read-write",
            "storage" => "configuration",
            "restart-required" => "all-services"
        }},
        "operations" => undefined,
        "notifications" => undefined,
        "children" => {}
    }
}

This is all not that exciting. But what is when you start to write application specific health check. You do that by implementing org.eclipse.microprofile.health.HealthCheck and annotating class with org.eclipse.microprofile.health.Health.

The best practice is to implement a specific health check in a separate class and then will jboss global health check aggregates all the result from each health check to the overall health check result. So lets start to write a JPA health check.


package se.magnuskkarlsson.example.microprofile;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

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

@Health
@ApplicationScoped
public class JPAHealthCheck implements HealthCheck {

    private final Logger log = Logger.getLogger(JPAHealthCheck.class.getName());

    @PersistenceContext
    protected EntityManager em;

    @Override
    public HealthCheckResponse call() {
        Integer result = null;
        try {
            result = (Integer) em.createNativeQuery("SELECT 1").getSingleResult();
        } catch (Exception e) {
            log.log(Level.SEVERE, "Failed to perform JPA health check.", e);
        }
        boolean state = (result == 1) ? true : false;
        return HealthCheckResponse.named("jpa-health-check").withData("SELECT 1", result).state(state).build();
    }

}

Build, deploy and test.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
    "outcome" => "success",
    "result" => {
        "outcome" => "UP",
        "checks" => [{
            "name" => "health-test",
            "state" => "UP",
            "data" => {"JPA 'SELECT 1'" => "1"}
        }]
    }
}

Now build a second health check for disk space, but here we will deliberate hard code the output state to down, to test jboss aggregated state value.


package se.magnuskkarlsson.example.microprofile;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;

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

@Health
@ApplicationScoped
public class DiskSpaceHealthCheck implements HealthCheck {

    private final Logger log = Logger.getLogger(DiskSpaceHealthCheck.class.getName());

    @Override
    public HealthCheckResponse call() {
        File path = new File("/");
        long diskFreeInBytes = 0L;
        try {
            diskFreeInBytes = path.getUsableSpace();
        } catch (Exception e) {
            log.log(Level.SEVERE, "Failed to perform disk space health check.", e);
        }
        boolean state = false;
        return HealthCheckResponse.named("disk-space-health-check").withData(path.getAbsolutePath(), diskFreeInBytes)
                .state(state).build();
    }

}

Build, deploy and test.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
    "outcome" => "success",
    "result" => {
        "outcome" => "DOWN",
        "checks" => [
            {
                "name" => "jpa-health-check",
                "state" => "UP",
                "data" => {"SELECT 1" => 1}
            },
            {
                "name" => "disk-space-health-check",
                "state" => "DOWN",
                "data" => {"/" => 409898860544L}
            }
        ]
    }
}

As you can see the overall state is DOWN.

To get more inspiration for others health check, see spring boots health indicators - https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/health/AbstractHealthIndicator.html

And finally it is of interest to read the Eclipse Microprofile Health Specification.

No comments: