diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java index d6c60a4cd26c5..f0d47eaceec7e 100644 --- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java +++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java @@ -29,6 +29,7 @@ import io.quarkus.smallrye.health.runtime.SmallRyeLivenessHandler; import io.quarkus.smallrye.health.runtime.SmallRyeReadinessHandler; import io.quarkus.vertx.http.deployment.RouteBuildItem; +import io.quarkus.vertx.http.runtime.HandlerType; import io.smallrye.health.SmallRyeHealthReporter; class SmallRyeHealthProcessor { @@ -91,11 +92,13 @@ void build(SmallRyeHealthRecorder recorder, RecorderContext recorderContext, feature.produce(new FeatureBuildItem(FeatureBuildItem.SMALLRYE_HEALTH)); // Register the health handler - routes.produce(new RouteBuildItem(health.rootPath, new SmallRyeHealthHandler())); + routes.produce(new RouteBuildItem(health.rootPath, new SmallRyeHealthHandler(), HandlerType.BLOCKING)); routes.produce( - new RouteBuildItem(health.rootPath + health.livenessPath, new SmallRyeLivenessHandler())); + new RouteBuildItem(health.rootPath + health.livenessPath, new SmallRyeLivenessHandler(), + HandlerType.BLOCKING)); routes.produce( - new RouteBuildItem(health.rootPath + health.readinessPath, new SmallRyeReadinessHandler())); + new RouteBuildItem(health.rootPath + health.readinessPath, new SmallRyeReadinessHandler(), + HandlerType.BLOCKING)); // Make ArC discover the beans marked with the @Health qualifier beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(HEALTH)); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DispatchedThreadTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DispatchedThreadTest.java new file mode 100644 index 0000000000000..590514951ed18 --- /dev/null +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DispatchedThreadTest.java @@ -0,0 +1,77 @@ +package io.quarkus.smallrye.health.test; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; + +import javax.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Liveness; +import org.eclipse.microprofile.health.Readiness; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class DispatchedThreadTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(LivenessHealthCheckCapturingThread.class, ReadinessHealthCheckCapturingThread.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); + + @Test + public void check() { + RestAssured.when().get("/health/live").then() + .body("status", is("UP"), + "checks.status", contains("UP"), + "checks.name", contains("my-liveness-check"), + "checks.data.thread[0]", stringContainsInOrder("worker"), + "checks.data.thread[0]", not(stringContainsInOrder("loop")), + "checks.data.request[0]", is(true)); + + RestAssured.when().get("/health/ready").then() + .body("status", is("UP"), + "checks.status", contains("UP"), + "checks.name", contains("my-readiness-check"), + "checks.data.thread[0]", stringContainsInOrder("worker"), + "checks.data.thread[0]", not(stringContainsInOrder("loop")), + "checks.data.request[0]", is(true)); + } + + @ApplicationScoped + @Liveness + public static class LivenessHealthCheckCapturingThread implements HealthCheck { + @Override + public HealthCheckResponse call() { + return HealthCheckResponse.named("my-liveness-check") + .up() + .withData("thread", Thread.currentThread().getName()) + .withData("request", Arc.container().requestContext().isActive()) + .build(); + } + } + + @ApplicationScoped + @Readiness + public static class ReadinessHealthCheckCapturingThread implements HealthCheck { + @Override + public HealthCheckResponse call() { + return HealthCheckResponse.named("my-readiness-check") + .up() + .withData("thread", Thread.currentThread().getName()) + .withData("request", Arc.container().requestContext().isActive()) + .build(); + } + } + +} diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/RequestScopeHelper.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/RequestScopeHelper.java new file mode 100644 index 0000000000000..4a683148e7add --- /dev/null +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/RequestScopeHelper.java @@ -0,0 +1,25 @@ +package io.quarkus.smallrye.health.runtime; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ManagedContext; + +public class RequestScopeHelper { + + /** + * Activates the request scope is not yet activated. + * + * @return {@code true} if activated by this method, {@code false} if already activated. + */ + static boolean activeRequestScope() { + ManagedContext context = Arc.container().requestContext(); + if (!context.isActive()) { + context.activate(); + return true; + } + return false; + } + + private RequestScopeHelper() { + // avoid direct instantiation + } +} diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandler.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandler.java index 2c885dfd4ff46..a498eafa3beaa 100644 --- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandler.java +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeHealthHandler.java @@ -4,6 +4,7 @@ import javax.enterprise.inject.spi.CDI; +import io.quarkus.arc.Arc; import io.smallrye.health.SmallRyeHealth; import io.smallrye.health.SmallRyeHealthReporter; import io.vertx.core.Handler; @@ -17,17 +18,24 @@ public class SmallRyeHealthHandler implements Handler { @Override public void handle(RoutingContext event) { + boolean activated = RequestScopeHelper.activeRequestScope(); - SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); - SmallRyeHealth health = reporter.getHealth(); - HttpServerResponse resp = event.response(); - if (health.isDown()) { - resp.setStatusCode(503); - } - resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); + SmallRyeHealth health = reporter.getHealth(); + HttpServerResponse resp = event.response(); + if (health.isDown()) { + resp.setStatusCode(503); + } + resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - reporter.reportHealth(outputStream, health); - resp.end(Buffer.buffer(outputStream.toByteArray())); + reporter.reportHealth(outputStream, health); + resp.end(Buffer.buffer(outputStream.toByteArray())); + } finally { + if (activated) { + Arc.container().requestContext().terminate(); + } + } } } diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeLivenessHandler.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeLivenessHandler.java index 6b68fe3ed2206..4b02ad730cafb 100644 --- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeLivenessHandler.java +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeLivenessHandler.java @@ -20,6 +20,7 @@ import javax.enterprise.inject.spi.CDI; +import io.quarkus.arc.Arc; import io.smallrye.health.SmallRyeHealth; import io.smallrye.health.SmallRyeHealthReporter; import io.vertx.core.Handler; @@ -33,17 +34,24 @@ public class SmallRyeLivenessHandler implements Handler { @Override public void handle(RoutingContext event) { - - SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); - SmallRyeHealth health = reporter.getLiveness(); - HttpServerResponse resp = event.response(); - if (health.isDown()) { - resp.setStatusCode(503); + boolean activated = RequestScopeHelper.activeRequestScope(); + + try { + SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); + SmallRyeHealth health = reporter.getLiveness(); + HttpServerResponse resp = event.response(); + if (health.isDown()) { + resp.setStatusCode(503); + } + resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + reporter.reportHealth(outputStream, health); + resp.end(Buffer.buffer(outputStream.toByteArray())); + } finally { + if (activated) { + Arc.container().requestContext().terminate(); + } } - resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - reporter.reportHealth(outputStream, health); - resp.end(Buffer.buffer(outputStream.toByteArray())); } } diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeReadinessHandler.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeReadinessHandler.java index 80f7b51fe0e90..b93406dd3fe2a 100644 --- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeReadinessHandler.java +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/SmallRyeReadinessHandler.java @@ -20,6 +20,7 @@ import javax.enterprise.inject.spi.CDI; +import io.quarkus.arc.Arc; import io.smallrye.health.SmallRyeHealth; import io.smallrye.health.SmallRyeHealthReporter; import io.vertx.core.Handler; @@ -32,17 +33,24 @@ public class SmallRyeReadinessHandler implements Handler { @Override public void handle(RoutingContext event) { - - SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); - SmallRyeHealth health = reporter.getReadiness(); - HttpServerResponse resp = event.response(); - if (health.isDown()) { - resp.setStatusCode(503); + boolean activated = RequestScopeHelper.activeRequestScope(); + + try { + SmallRyeHealthReporter reporter = CDI.current().select(SmallRyeHealthReporter.class).get(); + SmallRyeHealth health = reporter.getReadiness(); + HttpServerResponse resp = event.response(); + if (health.isDown()) { + resp.setStatusCode(503); + } + resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + reporter.reportHealth(outputStream, health); + resp.end(Buffer.buffer(outputStream.toByteArray())); + } finally { + if (activated) { + Arc.container().requestContext().terminate(); + } } - resp.headers().set(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - reporter.reportHealth(outputStream, health); - resp.end(Buffer.buffer(outputStream.toByteArray())); } }