Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Groovy: Add Health Checks Using Ratpacked

DZone's Guide to

Groovy: Add Health Checks Using Ratpacked

There's an easy way to build in a feature that checks whether certain servers, like mail servers, are available for you app.

· Java Zone
Free Resource

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

In the Ratpack core we can find the ratpack.health.HealthCheck interface. We can implement this interface to check for example if a mail server, that we need in our application, is available. Any objects that implement this interface and are registered in the Guice registry are handled by Ratpack. Ratpack also offers a HealthCheckHandler to output the results of all health checks or a single health check identified by a name. Instead of creating a new class that implements the HealthCheck interface we can also use the HealtCheck.of method. This method accepts an argument with the name of our check and a Closure or lambda expression with the code that does the checking.

Let's write a sample Ratpack application using the Groovy DSL. We first use the HealthCheck.of to implement a simple health check. We also using the HealthCheckHandler so we can request information about the health check.

// File: src/ratpack/Ratpack.groovy
import ratpack.exec.Promise
import ratpack.health.HealthCheck
import ratpack.health.HealthCheckHandler
import ratpack.registry.Registry

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        // Add a simple HealtCheck implementation with 
        // the of method. The name of our health check is
        // "application". We simply return a Promise with
        // a HealthCheck.Result value. If we get here we assume
        // the application is UP and running.
        add HealthCheck.of('application') { Registry registry ->
            Promise.value(HealthCheck.Result.healthy("UP"))
        }
    }

    handlers {
        // Assign HealthCheckHandler to health/ endpoint.
        // Optionally we can provide the name of the health check
        // to get the results specific for that health check.
        get('health/:name?', new HealthCheckHandler()) 
    }
}

When we run the application and request the URL http://localhost:5050/health and http://localhost:5050/health/application we get the following output:

$ http localhost:5050/health
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Expires: 0
Pragma: no-cache
connection: keep-alive
content-encoding: gzip
content-type: text/plain;charset=UTF-8
transfer-encoding: chunked

application : HEALTHY

$ http localhost:5050/health/application
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Expires: 0
Pragma: no-cache
connection: keep-alive
content-encoding: gzip
content-type: text/plain;charset=UTF-8
transfer-encoding: chunked

application : HEALTHY

Now we create a new class that implements the HealthCheck interface. We write a health check implementation that checks if the free space on a drive is less than a given threshold. If there is less space the health check should return an unhealthy status:

// File: src/main/groovy/com/mrhaki/ratpack/healthcheck/DiskSpaceHealthCheck.groovy
package com.mrhaki.ratpack.healthcheck

import groovy.transform.CompileStatic
import ratpack.exec.Blocking
import ratpack.exec.Promise
import ratpack.health.HealthCheck
import ratpack.registry.Registry

import static org.apache.commons.io.FileUtils.byteCountToDisplaySize

/**
 * Ratpack {@link HealthCheck} implementation to check for free space 
 * on a disk. If the available free space is less than a given
 * threshold value than the check return unhealthy.
 */
@CompileStatic
class DiskSpaceHealthCheck implements HealthCheck {

    /**
     *  Default disk to check for free space is the local
     * disk our Ratpack app is running. 
     */
    File path = new File(".")

    /**
     *  Default threshold is 50 MB. 
     */
    long threshold = 50L * 1024 * 1024

    /**
     * Name for health check. Name must be unique
     * in Ratpack application. To add more instances
     * of this class use different names.
     */
    String name = 'diskSpace'

    /**
     * Check available free space for the given {@link #path} value. Compare 
     * this with the configured {@link #threshold} value. If available free
     * space is less than threshold return unhealthy result.
     * Otherwise return a healthy status.
     * 
     * @param registry Ratpack registry.
     * @return Unhealthy result when available free space less than threshold, otherwise healthy.
     * @throws Exception Something goes wrong.
     */
    @Override
    Promise<HealthCheck.Result> check(final Registry registry) throws Exception {
        Blocking.get {

            // Get available free space. Operation is potentially blocking
            // so inside a Blocking.get{} block.
            path.freeSpace

        }.map { Long diskFreeSpace ->

            // Format bytes to readable format with KB, MB, GB, etc.
            final String diskFreeSpaceFormatted = byteCountToDisplaySize(diskFreeSpace)
            final String thresholdFormatted = byteCountToDisplaySize(threshold)

            // Check if available free space is above given threshold.
            if (diskFreeSpace >= threshold) {
                // Everything is ok.
                HealthCheck.Result.healthy(
                        'Available: %s (threshold: %s)',
                        diskFreeSpaceFormatted,
                        thresholdFormatted)
            } else {
                // Available free space is below given threshold.
                // Create message with information
                // and signal as unhealthy.
                HealthCheck.Result.unhealthy(
                        'Free disk space below threshold. Available: %s (threshold: %s)',
                        diskFreeSpaceFormatted,
                        thresholdFormatted)
            }
        }
    }
}

We only have to add this class to our registry and Ratpack will pick it up:

// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.healthcheck.DiskSpaceHealthCheck
import ratpack.exec.Promise
import ratpack.health.HealthCheck
import ratpack.health.HealthCheckHandler
import ratpack.registry.Registry

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        add new DiskSpaceHealthCheck(threshold: 50L * 1024 * 1024 * 1024 /* 50GB */)
        add HealthCheck.of('application') { Registry registry ->
            Promise.value(HealthCheck.Result.healthy("UP"))
        }
    }

    handlers {
        get('health/:name?', new HealthCheckHandler()) 
    }
}

We run the application and check the results of the health endpoint:

$ http localhost:5050/health
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Expires: 0
Pragma: no-cache
connection: keep-alive
content-encoding: gzip
content-type: text/plain;charset=UTF-8
transfer-encoding: chunked

application : HEALTHY
diskSpace : UNHEALTHY [Free disk space below threshold. Available: 41 GB (threshold: 50 GB)]

$ http localhost:5050/health/diskSpace
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate
Expires: 0
Pragma: no-cache
connection: keep-alive
content-encoding: gzip
content-type: text/plain;charset=UTF-8
transfer-encoding: chunked

diskSpace : UNHEALTHY [Free disk space below threshold. Available: 41 GB (threshold: 50 GB)]

Written with Ratpack 1.1.1.

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
groovy ,ratpacked

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}