Skip to content

Commit

Permalink
Add support for built-in health check config at health.checks while m…
Browse files Browse the repository at this point in the history
…aintaining bw compat at helidon.health

Signed-off-by: Tim Quinn <[email protected]>
  • Loading branch information
tjquinno committed Oct 8, 2024
1 parent c7c9a6e commit abada14
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 35 deletions.
9 changes: 4 additions & 5 deletions docs/se/health.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
:rootdir: {docdir}/..
include::{rootdir}/includes/se.adoc[]
:built-in-health-check-config-prefix: health.checks
== Contents
Expand Down Expand Up @@ -216,16 +217,14 @@ common health check statuses:
|available disk space
|`diskSpace`
| link:{health-javadoc-base-url}/io/helidon/health/checks/DiskSpaceHealthCheck.html[`DiskSpaceHealthCheck`]
|`helidon.healthCheck.diskSpace.thresholdPercent` +
+
`helidon.healthCheck.diskSpace.path`
|`{built-in-health-check-config-prefix}.diskSpace.thresholdPercent` +
`{built-in-health-check-config-prefix}.diskSpace.path`
| `99.999` +
+
`/`
|available heap memory
| `heapMemory`
| link:{health-javadoc-base-url}/io/helidon/health/checks/HeapMemoryHealthCheck.html[`HeapMemoryHealthCheck`]
|`helidon.healthCheck.heapMemory.thresholdPercent`
|`{built-in-health-check-config-prefix}.heapMemory.thresholdPercent`
|`98`
|=======
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.helidon.health.checks;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
Expand All @@ -26,12 +25,12 @@
import java.util.Locale;

import io.helidon.config.Config;
import io.helidon.config.DeprecatedConfig;
import io.helidon.health.HealthCheckException;
import io.helidon.health.common.BuiltInHealthCheck;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
Expand All @@ -43,7 +42,8 @@
* <p>
* By default, this health check has a threshold of 100%, meaning that it will never fail the threshold check.
* Also, by default, it will check the root path {@code /}. These defaults can be modified using the
* {@value CONFIG_KEY_PATH} property (default {@value DEFAULT_PATH}), and the {@value CONFIG_KEY_THRESHOLD_PERCENT}
* {@value CURRENT_CONFIG_KEY_PATH} property (default {@value DEFAULT_PATH}), and the
* {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT}
* property (default {@value DEFAULT_THRESHOLD}, virtually 100). The threshold should be set to a percent, such as 50 for 50% or
* 99 for 99%. If disk usage
* exceeds this threshold, then the health check will fail.
Expand All @@ -69,7 +69,7 @@ public class DiskSpaceHealthCheck implements HealthCheck {
* directory as application path), use
* {@link io.helidon.health.checks.DiskSpaceHealthCheck.Builder#path(java.nio.file.Path)}.
* When running within a MicroProfile server, you can configure path using a configuration key
* {@value #CONFIG_KEY_PATH}
* {@value #CURRENT_CONFIG_KEY_PATH}
* Defaults to {@value}
*/
public static final String DEFAULT_PATH = ".";
Expand All @@ -87,14 +87,25 @@ public class DiskSpaceHealthCheck implements HealthCheck {
/**
* Full configuration key for path, when configured through MicroProfile config.
*/
public static final String CONFIG_KEY_PATH = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
public static final String CONFIG_KEY_PATH = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_PATH_SUFFIX;

/**
* Full configuration key for threshold percent, when configured through Microprofile config.
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

// The following two constants are used in the Javadoc to nudge users toward using the config key prefix "health.checks"
// rather than the obsolete "helidon.health". Because the original public constants above have always referred to the
// now-deprecated config prefixes, those values are unchanged to preserve backward compatibility.
private static final String CURRENT_CONFIG_KEY_PATH = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_PATH_SUFFIX;

private static final String CURRENT_CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_DISKSPACE_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

Expand All @@ -114,16 +125,22 @@ public class DiskSpaceHealthCheck implements HealthCheck {
}

@Inject
DiskSpaceHealthCheck(
@ConfigProperty(name = CONFIG_KEY_PATH, defaultValue = DEFAULT_PATH) File path,
@ConfigProperty(name = CONFIG_KEY_THRESHOLD_PERCENT, defaultValue = "99.999") double thresholdPercent
) {
DiskSpaceHealthCheck(Config rootConfig) {
Config diskSpaceConfig = DeprecatedConfig.get(rootConfig,
HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX)
.get(CONFIG_KEY_DISKSPACE_PREFIX);
Path path = diskSpaceConfig.get(CONFIG_KEY_PATH_SUFFIX)
.as(Path.class)
.orElse(Paths.get("."));
thresholdPercent = diskSpaceConfig.get(CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX)
.asDouble()
.orElse(99.999d);
try {
this.fileStore = Files.getFileStore(path.toPath());
this.fileStore = Files.getFileStore(path);
} catch (IOException e) {
throw new HealthCheckException("Failed to obtain file store for path " + path.getAbsolutePath(), e);
throw new HealthCheckException("Failed to obtain file store for path " + path, e);
}
this.thresholdPercent = thresholdPercent;
}

private DiskSpaceHealthCheck(Builder builder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates.
* Copyright (c) 2018, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,7 +31,8 @@
*/
public final class HealthChecks {

static final String CONFIG_KEY_HEALTH_PREFIX = "helidon.health";
static final String CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX = "health.checks";
static final String DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX = "helidon.health";

private HealthChecks() {
}
Expand Down Expand Up @@ -114,9 +115,10 @@ public static HealthCheck[] healthChecks() {
}

/**
* Built-in health checks, set up using "helidon.health" configuration.
* Built-in health checks, set up using configuration at {@value CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX} or the deprecated
* {@value DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX}.
*
* @param config configuration rooted at "helidon.health"
* @param config configuration at the node containing health checks config
* @return built-in health checks, set up using the provided configuration
* @see io.helidon.health.HealthSupport.Builder#addLiveness(org.eclipse.microprofile.health.HealthCheck...)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
import java.util.Locale;

import io.helidon.config.Config;
import io.helidon.config.DeprecatedConfig;
import io.helidon.health.common.BuiltInHealthCheck;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
Expand All @@ -36,7 +36,7 @@
* By default, this health check has a threshold of {@value DEFAULT_THRESHOLD} ({@value DEFAULT_THRESHOLD}%).
* If heap usage exceeds this level, then the server
* is considered to be unhealthy. This default can be modified using the
* {@value CONFIG_KEY_THRESHOLD_PERCENT} property. The threshold should be set as a percent, such as
* {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} property. The threshold should be set as a percent, such as
* 50 for 50% or 99 for 99%.
* </p>
* <p>
Expand All @@ -63,20 +63,38 @@ public class HeapMemoryHealthCheck implements HealthCheck {
/**
* Config property key for heap memory threshold.
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_HEAP_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;

// The following constant is used in the Javadoc to nudge users toward using the current config key prefix "health.checks"
// rather than the deprecated "helidon.health". The public constant above has always used the now-deprecated prefix so that
// value is unchanged to preserve backward compatibility.
private static final String CURRENT_CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX
+ "." + CONFIG_KEY_HEAP_PREFIX
+ "." + CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX;


private final Runtime rt;
private final double thresholdPercent;

// this will be ignored if not within CDI
@Inject
HeapMemoryHealthCheck(
Runtime runtime,
@ConfigProperty(name = CONFIG_KEY_THRESHOLD_PERCENT, defaultValue = "98") double threshold) {
this.thresholdPercent = threshold;
Config rootConfig) {
this(runtime, DeprecatedConfig.get(rootConfig,
HealthChecks.CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX,
HealthChecks.DEPRECATED_CONFIG_KEY_BUILT_IN_HEALTH_CHECKS_PREFIX)
.get(CONFIG_KEY_HEAP_PREFIX)
.get(CONFIG_KEY_THRESHOLD_PERCENT_SUFFIX)
.asDouble()
.orElse(98d));
}

HeapMemoryHealthCheck(Runtime runtime, double thresholdPercent) {
this.rt = runtime;
this.thresholdPercent = thresholdPercent;
}

private HeapMemoryHealthCheck(Builder builder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,7 @@
import io.helidon.common.http.MediaType;
import io.helidon.config.Config;
import io.helidon.config.ConfigSources;
import io.helidon.config.DeprecatedConfig;
import io.helidon.health.HealthSupport;
import io.helidon.media.jsonp.JsonpSupport;
import io.helidon.webclient.WebClient;
Expand Down Expand Up @@ -69,7 +70,7 @@ static void shutdownServer(WebServer server) {

@Test
void bothFail() throws InterruptedException, ExecutionException, TimeoutException {
JsonObject health = runWithConfig("bothFail", Http.Status.SERVICE_UNAVAILABLE_503.code());
JsonObject health = runWithConfig("bothFailWithDeprecatedPrefix.helidon.health", Http.Status.SERVICE_UNAVAILABLE_503.code());
JsonObject diskSpace = getLivenessCheck(health, "diskSpace");

assertThat("Disk space liveness return data", diskSpace, is(notNullValue()));
Expand All @@ -83,7 +84,7 @@ void bothFail() throws InterruptedException, ExecutionException, TimeoutExceptio

@Test
void bothPass() throws InterruptedException, ExecutionException, TimeoutException {
JsonObject health = runWithConfig("bothPass", Http.Status.OK_200.code());
JsonObject health = runWithConfig("bothPassWithDeprecatedPrefix.helidon.health", Http.Status.OK_200.code());
JsonObject diskSpace = getLivenessCheck(health, "diskSpace");

assertThat("Disk space liveness return data", diskSpace, is(notNullValue()));
Expand All @@ -95,10 +96,25 @@ void bothPass() throws InterruptedException, ExecutionException, TimeoutExceptio
assertThat("Heap memory liveness check status", heapMemory.getString("status"), is("UP"));
}

@Test
void testWithoutHelidonPrefix() throws ExecutionException, InterruptedException, TimeoutException {
JsonObject health = runWithConfig("bothFailWithoutDeprecatedHelidonPrefix.health.checks",
Http.Status.SERVICE_UNAVAILABLE_503.code());
JsonObject diskSpace = getLivenessCheck(health, "diskSpace");

assertThat("Disk space liveness return data", diskSpace, is(notNullValue()));
assertThat("Disk space liveness check status", diskSpace.getString("status"), is("DOWN"));

JsonObject heapMemory = getLivenessCheck(health, "heapMemory");

assertThat("Heap memory liveness return data", heapMemory, is(notNullValue()));
assertThat("Heap memory liveness check status", heapMemory.getString("status"), is("DOWN"));
}

private JsonObject runWithConfig(String configKey, int expectedStatus) throws InterruptedException, ExecutionException,
TimeoutException {
HealthSupport healthSupport = HealthSupport.builder()
.addLiveness(HealthChecks.healthChecks(testConfig.get(configKey + ".helidon.health")))
.addLiveness(HealthChecks.healthChecks(testConfig.get(configKey)))
.build();
WebServer webServer = null;
try {
Expand Down
16 changes: 12 additions & 4 deletions health/health-checks/src/test/resources/testConfig.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2021 Oracle and/or its affiliates.
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -13,17 +13,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
bothFail:
bothFailWithDeprecatedPrefix:
helidon:
health:
diskSpace:
thresholdPercent: 0.0
heapMemory:
thresholdPercent: 0.0
bothPass:
bothPassWithDeprecatedPrefix:
helidon:
health:
diskSpace:
thresholdPercent: 98.1
heapMemory:
thresholdPercent: 98.1
thresholdPercent: 98.1
# Following are set to zero to avoid the defaults and force a DOWN state the test can easily detect.
bothFailWithoutDeprecatedHelidonPrefix:
health:
checks:
diskSpace:
thresholdPercent: 0.0
heapMemory:
thresholdPercent: 0.0
5 changes: 5 additions & 0 deletions microprofile/health/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
<groupId>io.helidon.service-common</groupId>
<artifactId>helidon-service-common-rest-cdi</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.health</groupId>
<artifactId>helidon-health-checks</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.microprofile.health;

import io.helidon.microprofile.tests.junit5.AddConfig;
import io.helidon.microprofile.tests.junit5.HelidonTest;

import jakarta.inject.Inject;
import jakarta.ws.rs.client.WebTarget;
import org.junit.jupiter.api.Test;

/**
* Tests the config prefix.
* <p>
* We specify 0 values to force the statuses to DOWN. The default config settings cause the checks to return UP, so if we
* detect DOWN statuses we know the config has been found and applied correctly.
*/
@HelidonTest
@AddConfig(key = "health.checks.diskSpace.thresholdPercent", value = "0.0")
@AddConfig(key = "health.checks.heapMemory.thresholdPercent", value = "0.0")
class TestConfigPrefix {

@Inject
private WebTarget webTarget;

@Test
void testConfig() {
TestUtils.checkForFailure(webTarget);
}
}
Loading

0 comments on commit abada14

Please sign in to comment.