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.
Join the DZone community and get the full member experience.
Join For FreeIn 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.
Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments