Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.x: Support built-in health check config at health.checks (retaining now-deprecated helidon.health for compatibility) #9337

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -86,15 +86,32 @@ public class DiskSpaceHealthCheck implements HealthCheck {

/**
* Full configuration key for path, when configured through MicroProfile config.
*
* @deprecated The value will change to {@value CURRENT_CONFIG_KEY_PATH} in a future release
*/
public static final String CONFIG_KEY_PATH = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
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.
*
* @deprecated The value will change to {@value CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} in future release
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
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 +131,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 @@ -62,21 +62,42 @@ public class HeapMemoryHealthCheck implements HealthCheck {

/**
* Config property key for heap memory threshold.
*
* @deprecated The value will change to {@value #CURRENT_CONFIG_KEY_THRESHOLD_PERCENT} in a future release
*/
public static final String CONFIG_KEY_THRESHOLD_PERCENT = HealthChecks.CONFIG_KEY_HEALTH_PREFIX
@Deprecated(since = "3.2.11")
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
Loading