I am running a Java (zulu-openjdk:17.0.8.1) application with Payara (5.2022.5).
The application has a health check endpoint that calculates the current heap usage. It is set up according to the Eclipse MicroProfile Health Check API documentation (https://github.com/eclipse/microprofile-health/blob/main/README.adoc). Besides the status it returns some of the calculated values as well. I noticed that the values are not all updated as I would expect.
The heapUsage value is not updated after the first call to the endpoint.
{"status":"UP","checks":[{"name":"heap-usage","status":"UP","data":{"usedMemory":"4275572456","totalMemory":"6062866432","heapUsage":"0.04","threshold":"0.90",
"maxMemory":"10001317888"}}]}
{"status":"UP","checks":[{"name":"heap-usage","status":"UP","data":{"usedMemory":"3726759584","totalMemory":"5837422592","heapUsage":"0.04","threshold":"0.90",
"maxMemory":"10001317888"}}]}
Code Example:
public class HealthChecks {
@Produces
@Liveness
HealthCheck checkHeapUsage() {
return () -> HealthCheckResponse
.named("heap-usage")
.status(getHeapUsage() <= 0.9)
.withData("heapUsage", formatDecimal(getHeapUsage()))
.withData("threshold", formatDecimal(0.9))
.withData("usedMemory", getUsedMemory())
.withData("maxMemory", getMaxMemory())
.withData("totalMemory", getTotalMemory())
.build();
}
private String formatDecimal(double usage) {
NumberFormat format = new DecimalFormat("#0.00");
return format.format(usage);
}
private double getHeapUsage() {
return Long.valueOf(getUsedMemory()).doubleValue() / getMaxMemory();
}
private long getUsedMemory() {
return getTotalMemory() - Runtime.getRuntime().freeMemory();
}
private long getMaxMemory() {
return Runtime.getRuntime().maxMemory();
}
private long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
}
I suspected the formatDecimal method could be the issue and cast the value to a long instead. With this change none of the values are updated anymore.
{"status":"UP","checks":[{"name":"heap-usage","status":"UP","data":{"usedMemory":"4275572456","totalMemory":"6062866432","heapUsage":"0.04","threshold":"0.90",
"maxMemory":"10001317888"}}]}
{"status":"UP","checks":[{"name":"heap-usage","status":"UP","data":{"usedMemory":"4275572456","totalMemory":"6062866432","heapUsage":"0.04","threshold":"0.90",
"maxMemory":"10001317888"}}]}
Code Example:
@Produces
@Liveness
HealthCheck checkHeapUsage() {
return () -> HealthCheckResponse
.named("heap-usage")
.status(getHeapUsage() <= 0.9)
.withData("heapUsage", (long) getHeapUsage())
.withData("threshold", formatDecimal(0.9))
.withData("usedMemory", getUsedMemory())
.withData("maxMemory", getMaxMemory())
.withData("totalMemory", getTotalMemory())
.build();
}
Can somebody please provide insights why this is the case and how to get new values when calling the endpoint.
Thanks very much!