Custom Health Checks when Using Spring Boot Actuator

Custom Health Endpoints with Actuator

Introduction to Actuator Health Check

There is a Spring Boot add-on known as Actuator which provides a user insight into the Spring environment for a running application. It has several endpoints, and a full discussion of this functionality can be found in the Actuator Documentation

One of the more interesting endpoints provided by Actuator is /health. This endpoint will provide an indication of the general health of the application, and for each of the @Component classes that implement the HealthIndicator interface, will actually check the health of that component. By default, all standard components (such as DataSource) implement this interface. The HealthCheck provided by a DataSource is to make a connection to a database and perform a simple query, such as select 1 from dual against an Oracle DataBase.

Adding a Custom Check

There will be a case where the functionality of a Component will be outside of what Spring naturally provides, and a custom health check will be required. In order to accomplish this, simply create a class that implements the HealthIndicator interface and annotate it with @Component to pull it into the Spring context. The following example performs a health check against a cache, a data source, and a remote (SOAP or Rest) service:

    @Override
    public Health health() {
        // check cache is available
        Cache cache = cacheManager.getCache("mycache");
        if (cache == null) {
            LOG.warn("Cache not available");
            return Health.down().withDetail("smoke test", "cache not available").build();
        }

        // check db available
        try (Connection connection = dataSource.getConnection()) {
        } catch (SQLException e) {
            LOG.warn("DB not available");
            return Health.down().withDetail("smoke test", e.getMessage()).build();
        }

        // check some service url is reachable
        try {
            URL url = new URL(resUrl);
            int port = url.getPort();
            if (port == -1) {
                port = url.getDefaultPort();
            }

            try (Socket socket = new Socket(url.getHost(), port)) {
            } catch (IOException e) {
                LOG.warn("Failed to open socket to " + resUrl);
                return Health.down().withDetail("smoke test", e.getMessage()).build();
            }
        } catch (MalformedURLException e1) {
            LOG.warn("Malformed URL: " + resUrl);
            return Health.down().withDetail("smoke test", e1.getMessage()).build();
        }

        return Health.up().build();
    }

Implementing a custom health check class is preferred to adding this code directly to a smoke test controller, as it takes full advantage of the Actuator framework.

Questions?