From 338a5efe57731b6ebd0b4508708f83ff8ff33942 Mon Sep 17 00:00:00 2001 From: xstefank Date: Thu, 29 Aug 2024 10:33:52 +0200 Subject: [PATCH] Destroy Dependent health checks --- .../health/SmallRyeHealthReporter.java | 32 ++++++++ .../deployment/AsyncDependentHealthCheck.java | 25 ++++++ .../deployment/DependentCallRecorder.java | 8 ++ .../deployment/DependentHealthCheck.java | 23 ++++++ .../test/DependentHealthChecksTest.java | 76 +++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 testsuite/experimental/src/test/java/io/smallrye/health/deployment/AsyncDependentHealthCheck.java create mode 100644 testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentCallRecorder.java create mode 100644 testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentHealthCheck.java create mode 100644 testsuite/experimental/src/test/java/io/smallrye/health/test/DependentHealthChecksTest.java diff --git a/implementation/src/main/java/io/smallrye/health/SmallRyeHealthReporter.java b/implementation/src/main/java/io/smallrye/health/SmallRyeHealthReporter.java index ace555c..89bd1eb 100644 --- a/implementation/src/main/java/io/smallrye/health/SmallRyeHealthReporter.java +++ b/implementation/src/main/java/io/smallrye/health/SmallRyeHealthReporter.java @@ -20,6 +20,7 @@ import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Dependent; import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.spi.Bean; @@ -190,6 +191,37 @@ private synchronized void initChecks() { checksInitialized = true; } + private void initUnis(List> list, Instance checks, + Instance asyncChecks) { + if (checks != null) { + for (Instance.Handle handle : checks.handles()) { + HealthCheck check = handle.get(); + if (check != null && isHealthCheckEnabled(check)) { + list.add(asyncHealthCheckFactory.callSync(check).chain(response -> { + if (handle.getBean().getScope().equals(Dependent.class)) { + handle.destroy(); + } + return Uni.createFrom().item(response); + })); + } + } + } + + if (asyncChecks != null) { + for (Instance.Handle handle : asyncChecks.handles()) { + AsyncHealthCheck asyncCheck = handle.get(); + if (asyncCheck != null && isHealthCheckEnabled(asyncCheck)) { + list.add(asyncHealthCheckFactory.callAsync(asyncCheck).chain(response -> { + if (handle.getBean().getScope().equals(Dependent.class)) { + handle.destroy(); + } + return Uni.createFrom().item(response); + })); + } + } + } + } + private void initUnis(List> list, Iterable checks, Iterable asyncChecks) { if (checks != null) { diff --git a/testsuite/experimental/src/test/java/io/smallrye/health/deployment/AsyncDependentHealthCheck.java b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/AsyncDependentHealthCheck.java new file mode 100644 index 0000000..f733059 --- /dev/null +++ b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/AsyncDependentHealthCheck.java @@ -0,0 +1,25 @@ +package io.smallrye.health.deployment; + +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.Dependent; + +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Liveness; + +import io.smallrye.health.api.AsyncHealthCheck; +import io.smallrye.mutiny.Uni; + +@Dependent +@Liveness +public class AsyncDependentHealthCheck implements AsyncHealthCheck { + + @Override + public Uni call() { + return Uni.createFrom().item(HealthCheckResponse.up(AsyncDependentHealthCheck.class.getName())); + } + + @PreDestroy + public void preDestroy() { + DependentCallRecorder.asyncHealthCheckPreDestroyCalled = true; + } +} diff --git a/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentCallRecorder.java b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentCallRecorder.java new file mode 100644 index 0000000..e32fd76 --- /dev/null +++ b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentCallRecorder.java @@ -0,0 +1,8 @@ +package io.smallrye.health.deployment; + +public class DependentCallRecorder { + + public static volatile boolean healthCheckPreDestroyCalled = false; + public static volatile boolean asyncHealthCheckPreDestroyCalled = false; + +} diff --git a/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentHealthCheck.java b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentHealthCheck.java new file mode 100644 index 0000000..eb93ab3 --- /dev/null +++ b/testsuite/experimental/src/test/java/io/smallrye/health/deployment/DependentHealthCheck.java @@ -0,0 +1,23 @@ +package io.smallrye.health.deployment; + +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.Dependent; + +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Liveness; + +@Dependent +@Liveness +public class DependentHealthCheck implements HealthCheck { + + @Override + public org.eclipse.microprofile.health.HealthCheckResponse call() { + return HealthCheckResponse.up(DependentHealthCheck.class.getName()); + } + + @PreDestroy + public void preDestroy() { + DependentCallRecorder.healthCheckPreDestroyCalled = true; + } +} diff --git a/testsuite/experimental/src/test/java/io/smallrye/health/test/DependentHealthChecksTest.java b/testsuite/experimental/src/test/java/io/smallrye/health/test/DependentHealthChecksTest.java new file mode 100644 index 0000000..a95260e --- /dev/null +++ b/testsuite/experimental/src/test/java/io/smallrye/health/test/DependentHealthChecksTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICES file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package io.smallrye.health.test; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.shrinkwrap.api.Archive; +import org.testng.Assert; +import org.testng.annotations.Test; + +import io.smallrye.health.deployment.AsyncDependentHealthCheck; +import io.smallrye.health.deployment.DependentCallRecorder; +import io.smallrye.health.deployment.DependentHealthCheck; + +public class DependentHealthChecksTest extends TCKBase { + + @Deployment + public static Archive getDeployment() { + return DeploymentUtils.createWarFileWithClasses(DependentHealthChecksTest.class.getSimpleName(), + DependentHealthCheck.class, AsyncDependentHealthCheck.class, DependentCallRecorder.class, TCKBase.class); + } + + @Test + public void testAsyncLiveness() { + Response response = getUrlLiveContents(); + + // status code + Assert.assertEquals(response.getStatus(), 200); + + JsonObject json = readJson(response); + + // response size + JsonArray checks = json.getJsonArray("checks"); + Assert.assertEquals(checks.size(), 2, "Expected two check responses"); + + for (JsonObject check : checks.getValuesAs(JsonObject.class)) { + String id = check.getString("name"); + + if (id.equals(DependentHealthCheck.class.getName())) { + verifySuccessStatus(check); + Assert.assertTrue(DependentCallRecorder.healthCheckPreDestroyCalled, + "HealthCheck - PreDestroy method was not called"); + } else if (id.equals(AsyncDependentHealthCheck.class.getName())) { + verifySuccessStatus(check); + Assert.assertTrue(DependentCallRecorder.asyncHealthCheckPreDestroyCalled, + "AsyncHealthCheck - PreDestroy method was not called"); + } else { + Assert.fail("Unexpected response payload structure"); + } + } + + assertOverallSuccess(json); + } +}