diff --git a/core/deployment/src/main/java/io/quarkus/deployment/shutdown/ShutdownBuildTimeConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/shutdown/ShutdownBuildTimeConfig.java new file mode 100644 index 0000000000000..425b88aa59dd3 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/shutdown/ShutdownBuildTimeConfig.java @@ -0,0 +1,17 @@ +package io.quarkus.deployment.shutdown; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(phase = ConfigPhase.BUILD_TIME) +public class ShutdownBuildTimeConfig { + + /** + * Whether Quarkus should wait between shutdown being requested and actually initiated. + * This delay gives the infrastructure time to detect that the application instance is shutting down and + * stop routing traffic to it. + */ + @ConfigItem(defaultValue = "false") + public boolean delayEnabled; +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ShutdownListenerBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ShutdownListenerBuildStep.java index ec7d4438b2243..40271a1513e65 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ShutdownListenerBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ShutdownListenerBuildStep.java @@ -1,20 +1,21 @@ package io.quarkus.deployment.steps; import java.util.List; -import java.util.stream.Collectors; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.ExecutionTime; import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.ShutdownListenerBuildItem; +import io.quarkus.deployment.shutdown.ShutdownBuildTimeConfig; import io.quarkus.runtime.shutdown.ShutdownRecorder; public class ShutdownListenerBuildStep { @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - void setupShutdown(List listeners, ShutdownRecorder recorder) { - recorder.setListeners( - listeners.stream().map(ShutdownListenerBuildItem::getShutdownListener).collect(Collectors.toList())); + void setupShutdown(List listeners, ShutdownBuildTimeConfig shutdownBuildTimeConfig, + ShutdownRecorder recorder) { + recorder.setListeners(listeners.stream().map(ShutdownListenerBuildItem::getShutdownListener).toList(), + shutdownBuildTimeConfig.delayEnabled); } } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownConfig.java index 8c83803e98103..be79d04d1cf03 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownConfig.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownConfig.java @@ -18,8 +18,24 @@ public class ShutdownConfig { @ConfigItem public Optional timeout; + /** + * Delay between shutdown being requested and actually initiated. Also called the pre-shutdown phase. + * In pre-shutdown, the server continues working as usual, except a readiness probe starts reporting "down" + * (if the {@code smallrye-health} extension is present). This gives the infrastructure time to detect + * that the application instance is shutting down and stop routing traffic to it. + * + * Notice that this property will only take effect if {@code quarkus.shutdown.delay-enabled} is explicitly + * set to {@code true}. + */ + @ConfigItem + public Optional delay; + public boolean isShutdownTimeoutSet() { return timeout.isPresent() && timeout.get().toMillis() > 0; } + public boolean isDelaySet() { + return delay.isPresent() && delay.get().toMillis() > 0; + } + } diff --git a/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownRecorder.java b/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownRecorder.java index debd3a06ab658..ace0f19deb298 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownRecorder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/shutdown/ShutdownRecorder.java @@ -1,6 +1,5 @@ package io.quarkus.runtime.shutdown; -import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.concurrent.CountDownLatch; @@ -16,43 +15,55 @@ public class ShutdownRecorder { private static final Logger log = Logger.getLogger(ShutdownRecorder.class); private static volatile List shutdownListeners; - private static volatile Optional waitTime; - - final ShutdownConfig shutdownConfig; + private static volatile ShutdownConfig shutdownConfig; + private static volatile boolean delayEnabled; public ShutdownRecorder(ShutdownConfig shutdownConfig) { - this.shutdownConfig = shutdownConfig; + ShutdownRecorder.shutdownConfig = shutdownConfig; } - public void setListeners(List listeners) { - shutdownListeners = listeners; - waitTime = shutdownConfig.timeout; + public void setListeners(List listeners, boolean delayEnabled) { + shutdownListeners = Optional.ofNullable(listeners).orElseGet(List::of); + ShutdownRecorder.delayEnabled = delayEnabled; } public static void runShutdown() { - if (shutdownListeners == null) { - return; - } log.debug("Attempting to gracefully shutdown."); try { - CountDownLatch preShutdown = new CountDownLatch(shutdownListeners.size()); - for (ShutdownListener i : shutdownListeners) { - i.preShutdown(new LatchShutdownNotification(preShutdown)); - } + executePreShutdown(); + waitForDelay(); + executeShutdown(); + } catch (Throwable e) { + log.error("Graceful shutdown failed", e); + } + } - preShutdown.await(); - CountDownLatch shutdown = new CountDownLatch(shutdownListeners.size()); - for (ShutdownListener i : shutdownListeners) { - i.shutdown(new LatchShutdownNotification(shutdown)); - } - if (waitTime.isPresent()) { - if (!shutdown.await(waitTime.get().toMillis(), TimeUnit.MILLISECONDS)) { - log.error("Timed out waiting for graceful shutdown, shutting down anyway."); - } + private static void executePreShutdown() throws InterruptedException { + CountDownLatch preShutdown = new CountDownLatch(shutdownListeners.size()); + for (ShutdownListener i : shutdownListeners) { + i.preShutdown(new LatchShutdownNotification(preShutdown)); + } + preShutdown.await(); + } + + private static void waitForDelay() { + if (delayEnabled && shutdownConfig.isDelaySet()) { + try { + Thread.sleep(shutdownConfig.delay.get().toMillis()); + } catch (InterruptedException e) { + log.error("Interrupted while waiting for delay, continuing to shutdown immediately"); } + } + } - } catch (Throwable e) { - log.error("Graceful shutdown failed", e); + private static void executeShutdown() throws InterruptedException { + CountDownLatch shutdown = new CountDownLatch(shutdownListeners.size()); + for (ShutdownListener i : shutdownListeners) { + i.shutdown(new LatchShutdownNotification(shutdown)); + } + if (shutdownConfig.isShutdownTimeoutSet() + && !shutdown.await(shutdownConfig.timeout.get().toMillis(), TimeUnit.MILLISECONDS)) { + log.error("Timed out waiting for graceful shutdown, shutting down anyway."); } } diff --git a/docs/src/main/asciidoc/lifecycle.adoc b/docs/src/main/asciidoc/lifecycle.adoc index a528863ac6bf0..20e7ed5cdd38a 100644 --- a/docs/src/main/asciidoc/lifecycle.adoc +++ b/docs/src/main/asciidoc/lifecycle.adoc @@ -34,7 +34,8 @@ The solution is located in the `lifecycle-quickstart` link:{quickstarts-tree-url == Creating the Maven project -First, we need a new project. Create a new project with the following command: +First, we need a new project. +Create a new project with the following command: :create-app-artifact-id: lifecycle-quickstart include::{includes}/devtools/create-app.adoc[] @@ -47,8 +48,8 @@ It generates: == The main method -By default, Quarkus will automatically generate a main method, that will bootstrap Quarkus and then just wait for -shutdown to be initiated. Let's provide our own main method: +By default, Quarkus will automatically generate a main method, that will bootstrap Quarkus and then just wait for shutdown to be initiated. +Let's provide our own main method: [source,java] ---- package com.acme; @@ -68,20 +69,17 @@ public class Main { <1> This annotation tells Quarkus to use this as the main method, unless it is overridden in the config <2> This launches Quarkus -This main class will bootstrap Quarkus and run it until it stops. This is no different to the automatically -generated main class, but has the advantage that you can just launch it directly from the IDE without needing -to run a Maven or Gradle command. +This main class will bootstrap Quarkus and run it until it stops. +This is no different to the automatically generated main class, but has the advantage that you can just launch it directly from the IDE without needing to run a Maven or Gradle command. -WARNING: It is not recommenced to do any business logic in this main method, as Quarkus has not been set up yet, -and Quarkus may run in a different ClassLoader. If you want to perform logic on startup use an `io.quarkus.runtime.QuarkusApplication` -as described below. +WARNING: It is not recommenced to do any business logic in this main method, as Quarkus has not been set up yet, and Quarkus may run in a different ClassLoader. +If you want to perform logic on startup use an `io.quarkus.runtime.QuarkusApplication` as described below. -If we want to actually perform business logic on startup (or write applications that complete a task and then exit) -we need to supply a `io.quarkus.runtime.QuarkusApplication` class to the run method. After Quarkus has been started -the `run` method of the application will be invoked. When this method returns the Quarkus application will exit. +If we want to actually perform business logic on startup (or write applications that complete a task and then exit) we need to supply a `io.quarkus.runtime.QuarkusApplication` class to the run method. +After Quarkus has been started the `run` method of the application will be invoked. +When this method returns the Quarkus application will exit. -If you want to perform logic on startup you should call `Quarkus.waitForExit()`, this method will wait until a shutdown -is requested (either from an external signal like when you press `Ctrl+C` or because a thread has called `Quarkus.asyncExit()`). +If you want to perform logic on startup you should call `Quarkus.waitForExit()`, this method will wait until a shutdown is requested (either from an external signal like when you press `Ctrl+C` or because a thread has called `Quarkus.asyncExit()`). An example of what this looks like is below: @@ -176,8 +174,7 @@ include::{includes}/devtools/dev-parameters.adoc[] == Listening for startup and shutdown events -Create a new class named `AppLifecycleBean` (or pick another name) in the `org.acme.lifecycle` package, and copy the -following content: +Create a new class named `AppLifecycleBean` (or pick another name) in the `org.acme.lifecycle` package, and copy the following content: [source,java] ---- @@ -210,7 +207,8 @@ public class AppLifecycleBean { TIP: The events are also called in _dev mode_ between each redeployment. -NOTE: The methods can access injected beans. Check the link:{quickstarts-blob-url}/lifecycle-quickstart/src/main/java/org/acme/lifecycle/AppLifecycleBean.java[AppLifecycleBean.java] class for details. +NOTE: The methods can access injected beans. +Check the link:{quickstarts-blob-url}/lifecycle-quickstart/src/main/java/org/acme/lifecycle/AppLifecycleBean.java[AppLifecycleBean.java] class for details. === What is the difference from `@Initialized(ApplicationScoped.class)` and `@Destroyed(ApplicationScoped.class)` @@ -322,19 +320,24 @@ include::{includes}/devtools/build-native.adoc[] == Launch Modes -Quarkus has 3 different launch modes, `NORMAL` (i.e. production), `DEVELOPMENT` and `TEST`. If you are running `quarkus:dev` -then the mode will be `DEVELOPMENT`, if you are running a JUnit test it will be `TEST`, otherwise it will be `NORMAL`. +Quarkus has 3 different launch modes, `NORMAL` (i.e. production), `DEVELOPMENT` and `TEST`. +If you are running `quarkus:dev` then the mode will be `DEVELOPMENT`, if you are running a JUnit test it will be `TEST`, otherwise it will be `NORMAL`. -Your application can get the launch mode by injecting the `io.quarkus.runtime.LaunchMode` enum into a CDI bean, -or by invoking the static method `io.quarkus.runtime.LaunchMode.current()`. +Your application can get the launch mode by injecting the `io.quarkus.runtime.LaunchMode` enum into a CDI bean, or by invoking the static method `io.quarkus.runtime.LaunchMode.current()`. == Graceful Shutdown -Quarkus includes support for graceful shutdown, this allows Quarkus to wait for running requests to finish, up -till a set timeout. By default, this is disabled, however you can configure this by setting the `quarkus.shutdown.timeout` -config property. When this is set shutdown will not happen until all running requests have completed, or until -this timeout has elapsed. This config property is a duration, and can be set using the standard -`java.time.Duration` format, if only a number is specified it is interpreted as seconds. +Quarkus includes support for graceful shutdown, this allows Quarkus to wait for running requests to finish, up till a set timeout. +By default, this is disabled, however you can configure this by setting the `quarkus.shutdown.timeout` config property. +When this is set shutdown will not happen until all running requests have completed, or until this timeout has elapsed. -Extensions that accept requests need to add support for this on an individual basis. At the moment only the -HTTP extension supports this, so shutdown may still happen when messaging requests are active. +Extensions that accept requests need to add support for this on an individual basis. +At the moment only the HTTP extension supports this, so shutdown may still happen when messaging requests are active. + +Quarkus supports a delay time, where the application instance still responds to requests, but the readiness probe fails. +This gives the infrastructure time to recognize that the instance is shutting down and stop routing traffic to the instance. +This feature can be enabled by setting the build-time property `quarkus.shutdown.delay-enabled` to `true`. +The delay can then be configured by setting the runtime property `quarkus.shutdown.delay`. +It is not set by default, thus no delay is applied. + +include::{includes}/duration-format-note.adoc[] \ No newline at end of file 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 69d292bd81634..8b7101bf10751 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 @@ -9,7 +9,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.BooleanSupplier; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.microprofile.config.Config; @@ -45,6 +44,7 @@ import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem; import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.ShutdownListenerBuildItem; +import io.quarkus.deployment.shutdown.ShutdownBuildTimeConfig; import io.quarkus.deployment.util.ServiceUtil; import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem; import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem; @@ -54,6 +54,7 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem; import io.quarkus.smallrye.health.runtime.QuarkusAsyncHealthCheckFactory; +import io.quarkus.smallrye.health.runtime.ShutdownReadinessCheck; import io.quarkus.smallrye.health.runtime.ShutdownReadinessListener; import io.quarkus.smallrye.health.runtime.SmallRyeHealthGroupHandler; import io.quarkus.smallrye.health.runtime.SmallRyeHealthHandler; @@ -82,6 +83,8 @@ class SmallRyeHealthProcessor { private static final Logger LOG = Logger.getLogger(SmallRyeHealthProcessor.class); + private static final String CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED = "quarkus.smallrye-health.management.enabled"; + private static final DotName LIVENESS = DotName.createSimple(Liveness.class.getName()); private static final DotName READINESS = DotName.createSimple(Readiness.class.getName()); private static final DotName STARTUP = DotName.createSimple(Startup.class.getName()); @@ -132,7 +135,7 @@ List brandingFiles() { BRANDING_LOGO_MODULE, BRANDING_STYLE_MODULE, BRANDING_FAVICON_MODULE).map(HotDeploymentWatchedFileBuildItem::new) - .collect(Collectors.toList()); + .toList(); } @BuildStep @@ -211,7 +214,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the health handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .route(healthConfig.rootPath) .routeConfigKey("quarkus.smallrye-health.root-path") .handler(new SmallRyeHealthHandler()) @@ -220,7 +223,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the liveness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.livenessPath) .handler(new SmallRyeLivenessHandler()) .displayOnNotFoundPage() @@ -228,7 +231,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the readiness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.readinessPath) .handler(new SmallRyeReadinessHandler()) .displayOnNotFoundPage() @@ -236,7 +239,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the health group handlers routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.groupPath) .handler(new SmallRyeHealthGroupHandler()) .displayOnNotFoundPage() @@ -244,7 +247,7 @@ public void defineHealthRoutes(BuildProducer routes, SmallRyeIndividualHealthGroupHandler handler = new SmallRyeIndividualHealthGroupHandler(); routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.groupPath + "/*") .handler(handler) .displayOnNotFoundPage() @@ -252,7 +255,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the wellness handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.wellnessPath) .handler(new SmallRyeWellnessHandler()) .displayOnNotFoundPage() @@ -260,7 +263,7 @@ public void defineHealthRoutes(BuildProducer routes, // Register the startup handler routes.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .nestedRoute(healthConfig.rootPath, healthConfig.startupPath) .handler(new SmallRyeStartupHandler()) .displayOnNotFoundPage() @@ -314,10 +317,9 @@ private void warnIfJaxRsPathUsed(IndexView index, DotName healthAnnotation) { if (target.asClass().declaredAnnotation(JAX_RS_PATH) != null) { containsPath = true; } - } else if (target.kind() == Kind.METHOD) { - if (target.asMethod().hasAnnotation(JAX_RS_PATH)) { - containsPath = true; - } + } else if (target.kind() == Kind.METHOD && target.asMethod().hasAnnotation(JAX_RS_PATH)) { + containsPath = true; + } if (containsPath) { LOG.warnv( @@ -355,6 +357,17 @@ public void kubernetes(NonApplicationRootPathBuildItem nonApplicationRootPathBui healthConfig.startupPath))); } + @BuildStep + void shutdownHealthCheck(ShutdownBuildTimeConfig buildTimeConfig, + BuildProducer additionalBeanProducer) { + if (buildTimeConfig.delayEnabled) { + additionalBeanProducer.produce(AdditionalBeanBuildItem.builder() + .addBeanClass(ShutdownReadinessCheck.class) + .setUnremovable() + .build()); + } + } + @BuildStep ShutdownListenerBuildItem shutdownListener() { return new ShutdownListenerBuildItem(new ShutdownReadinessListener()); @@ -413,7 +426,6 @@ void registerHealthUiHandler( LaunchModeBuildItem launchMode, SmallRyeHealthConfig healthConfig, BuildProducer smallryeHealthBuildProducer, ShutdownContextBuildItem shutdownContext) { - WebJarResultsBuildItem.WebJarResult result = webJarResultsBuildItem.byArtifactKey(HEALTH_UI_WEBJAR_ARTIFACT_KEY); if (result == null) { return; @@ -428,7 +440,7 @@ void registerHealthUiHandler( healthUiPath, result.getWebRootConfigurations(), runtimeConfig, shutdownContext); routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .route(healthConfig.ui.rootPath) .displayOnNotFoundPage("Health UI") .routeConfigKey("quarkus.smallrye-health.ui.root-path") @@ -436,7 +448,7 @@ void registerHealthUiHandler( .build()); routeProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() - .management("quarkus.smallrye-health.management.enabled") + .management(CONFIG_KEY_HEALTH_MANAGEMENT_ENABLED) .route(healthConfig.ui.rootPath + "*") .handler(handler) .build()); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AdditionalJsonPropertiesConfigTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AdditionalJsonPropertiesConfigTest.java index 9ad98853197c6..60df6532d86d2 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AdditionalJsonPropertiesConfigTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AdditionalJsonPropertiesConfigTest.java @@ -11,7 +11,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class AdditionalJsonPropertiesConfigTest { +class AdditionalJsonPropertiesConfigTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -22,7 +22,7 @@ public class AdditionalJsonPropertiesConfigTest { .overrideConfigKey("quarkus.smallrye-health.additional.property.testProp2", "testValue2"); @Test - public void testAdditionalJsonPropertyInclusions() { + void testAdditionalJsonPropertyInclusions() { try { RestAssured.defaultParser = Parser.JSON; RestAssured.when().get("/q/health").then() diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AsyncDispatchedThreadTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AsyncDispatchedThreadTest.java index 5030989f53c5e..a95d42322c4d1 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AsyncDispatchedThreadTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/AsyncDispatchedThreadTest.java @@ -20,7 +20,7 @@ import io.smallrye.health.api.AsyncHealthCheck; import io.smallrye.mutiny.Uni; -public class AsyncDispatchedThreadTest { +class AsyncDispatchedThreadTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -29,7 +29,7 @@ public class AsyncDispatchedThreadTest { .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); @Test - public void check() { + void check() { RestAssured.when().get("/q/health/live").then() .body("status", is("UP"), "checks.status", contains("UP"), diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BasicHealthCheck.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BasicHealthCheck.java index 6d6e53dc8011f..d3878da78a9ba 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BasicHealthCheck.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BasicHealthCheck.java @@ -12,7 +12,7 @@ @Dependent @Liveness -public class BasicHealthCheck implements HealthCheck { +class BasicHealthCheck implements HealthCheck { @Override public HealthCheckResponse call() { diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BlockingNonBlockingTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BlockingNonBlockingTest.java index d1ef2e076d593..88589a4dc9501 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BlockingNonBlockingTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/BlockingNonBlockingTest.java @@ -24,7 +24,7 @@ import io.smallrye.health.SmallRyeHealthReporter; import io.smallrye.mutiny.Uni; -public class BlockingNonBlockingTest { +class BlockingNonBlockingTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -33,7 +33,7 @@ public class BlockingNonBlockingTest { .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); @Test - public void testRegisterHealthOnBlockingThreadStep1() { + void testRegisterHealthOnBlockingThreadStep1() { // initial startup health blocking call on worker thread given() .when().get("/start-health") diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DefaultHealthGroupTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DefaultHealthGroupTest.java index a750c84e234b4..7c8d8708e23fd 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DefaultHealthGroupTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DefaultHealthGroupTest.java @@ -13,7 +13,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class DefaultHealthGroupTest { +class DefaultHealthGroupTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -23,7 +23,7 @@ public class DefaultHealthGroupTest { .overrideConfigKey("quarkus.smallrye-health.default-health-group", "my-default-health-group"); @Test - public void testDefaultHealthGroup() { + void testDefaultHealthGroup() { try { RestAssured.defaultParser = Parser.JSON; RestAssured.when().get("/q/health/group/my-default-health-group").then() diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DisableHealthCheckTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DisableHealthCheckTest.java index b24269014ab80..d2984a3807dcc 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DisableHealthCheckTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/DisableHealthCheckTest.java @@ -10,7 +10,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class DisableHealthCheckTest { +class DisableHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -21,7 +21,7 @@ public class DisableHealthCheckTest { + BasicHealthCheck.class.getName() + "\".enabled", "false"); @Test - public void testHealthCheckDisabled() { + void testHealthCheckDisabled() { try { RestAssured.defaultParser = Parser.JSON; RestAssured.when().get("/q/health").then() 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 index b36e48a87b1f7..85eca58cd9a39 100644 --- 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 @@ -19,7 +19,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DispatchedThreadTest { +class DispatchedThreadTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -28,7 +28,7 @@ public class DispatchedThreadTest { .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); @Test - public void check() { + void check() { RestAssured.when().get("/q/health/live").then() .body("status", is("UP"), "checks.status", contains("UP"), diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ExpectedBeansUnitTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ExpectedBeansUnitTest.java index 54239eb3f9862..347d822ac85c9 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ExpectedBeansUnitTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ExpectedBeansUnitTest.java @@ -17,7 +17,7 @@ import io.smallrye.health.SmallRyeHealthReporter; import io.smallrye.health.api.HealthGroup; -public class ExpectedBeansUnitTest { +class ExpectedBeansUnitTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -39,7 +39,7 @@ private boolean isUnique(Instance instances) { * Test that SmallRye Health Reporter is registered and unique */ @Test - public void testReporterIsUnique() { + void testReporterIsUnique() { Assertions.assertTrue(isUnique(reporters)); } @@ -47,7 +47,7 @@ public void testReporterIsUnique() { * Test that HealthCheck procedure beans are registered once */ @Test - public void testHealthCheckIsUnique() { + void testHealthCheckIsUnique() { Assertions.assertTrue(isUnique(checks)); } @@ -55,7 +55,7 @@ public void testHealthCheckIsUnique() { * Test metadata on HealthCheck procedure beans */ @Test - public void testHealthCheckMetadata() { + void testHealthCheckMetadata() { Instance selects; selects = checks.select(Liveness.Literal.INSTANCE); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingHealthCheck.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingHealthCheck.java index 0c49c56be7b76..e10a7a1025525 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingHealthCheck.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingHealthCheck.java @@ -20,7 +20,7 @@ @Startup @HealthGroup("group1") @HealthGroup("group2") -public class FailingHealthCheck implements HealthCheck { +class FailingHealthCheck implements HealthCheck { @Override public HealthCheckResponse call() { diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingUnitTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingUnitTest.java index 4c069818555f9..53dea5ac68f90 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingUnitTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/FailingUnitTest.java @@ -18,7 +18,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class FailingUnitTest { +class FailingUnitTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -30,7 +30,7 @@ public class FailingUnitTest { Instance checks; @Test - public void testHealthServlet() { + void testHealthServlet() { RestAssured.when().get("/q/health/live").then().statusCode(503); RestAssured.when().get("/q/health/ready").then().statusCode(503); RestAssured.when().get("/q/health/started").then().statusCode(503); @@ -38,7 +38,7 @@ public void testHealthServlet() { } @Test - public void testHealthBeans() { + void testHealthBeans() { List check = new ArrayList<>(); for (HealthCheck i : checks) { check.add(i); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java index 0d843d56cb901..1a1aa74408175 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckContextPropagationTest.java @@ -23,7 +23,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckContextPropagationTest { +class HealthCheckContextPropagationTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -32,7 +32,7 @@ public class HealthCheckContextPropagationTest { .addClasses(RequestScopedBean.class, ContextualHC.class)); @Test - public void testContextPropagatedToHealthChecks() { + void testContextPropagatedToHealthChecks() { try { RestAssured.defaultParser = Parser.JSON; diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckDefaultScopeTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckDefaultScopeTest.java index 7aac837a9b72f..0e1707563dc13 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckDefaultScopeTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckDefaultScopeTest.java @@ -5,12 +5,12 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.util.concurrent.atomic.AtomicInteger; import jakarta.enterprise.inject.Stereotype; import jakarta.inject.Named; @@ -25,7 +25,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckDefaultScopeTest { +class HealthCheckDefaultScopeTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -33,18 +33,18 @@ public class HealthCheckDefaultScopeTest { .addClasses(NoScopeCheck.class, NoScopeStereotypeWithoutScopeCheck.class, MyStereotype.class)); @Test - public void testHealth() { + void testHealth() { // the health check does not set a content type, so we need to force the parser try { RestAssured.defaultParser = Parser.JSON; when().get("/q/health/live").then() .body("status", is("UP"), - "checks.status", contains("UP", "UP"), - "checks.name", containsInAnyOrder("noScope", "noScopeStereotype")); + "checks.status", hasItems("UP", "UP"), + "checks.name", hasItems("noScope", "noScopeStereotype")); when().get("/q/health/live").then() .body("status", is("DOWN"), - "checks.status", contains("DOWN", "DOWN"), - "checks.name", containsInAnyOrder("noScope", "noScopeStereotype")); + "checks.status", hasItems("DOWN", "DOWN"), + "checks.name", hasItems("noScope", "noScopeStereotype")); } finally { RestAssured.reset(); } @@ -54,11 +54,11 @@ public void testHealth() { @Liveness static class NoScopeCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("noScope").build(); } return HealthCheckResponse.builder().up().name("noScope").build(); @@ -70,11 +70,11 @@ public HealthCheckResponse call() { @Liveness static class NoScopeStereotypeWithoutScopeCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("noScopeStereotype").build(); } return HealthCheckResponse.builder().up().name("noScopeStereotype").build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceDisabledTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceDisabledTest.java index 33f48e3d16cbb..607f0cfc4e37b 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceDisabledTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceDisabledTest.java @@ -2,9 +2,11 @@ import static io.restassured.RestAssured.when; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; +import java.util.concurrent.atomic.AtomicInteger; + import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Liveness; @@ -15,7 +17,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckOnManagementInterfaceDisabledTest { +class HealthCheckOnManagementInterfaceDisabledTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -24,17 +26,17 @@ public class HealthCheckOnManagementInterfaceDisabledTest { .overrideConfigKey("quarkus.management.enabled", "false"); @Test - public void testHealth() { + void testHealth() { try { RestAssured.defaultParser = Parser.JSON; when().get("/q/health/live").then() .body("status", is("UP"), "checks.status", contains("UP"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", hasItems("my-check")); when().get("/q/health/live").then() .body("status", is("DOWN"), "checks.status", contains("DOWN"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", hasItems("my-check")); } finally { RestAssured.reset(); } @@ -43,11 +45,11 @@ public void testHealth() { @Liveness static class MyCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("my-check").build(); } return HealthCheckResponse.builder().up().name("my-check").build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceTest.java index 8a5a168ff3597..e50580e2e6d54 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceTest.java @@ -1,11 +1,11 @@ package io.quarkus.smallrye.health.test; -import static io.restassured.RestAssured.get; import static io.restassured.RestAssured.when; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import java.util.concurrent.atomic.AtomicInteger; + import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Liveness; @@ -16,7 +16,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckOnManagementInterfaceTest { +class HealthCheckOnManagementInterfaceTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -25,17 +25,17 @@ public class HealthCheckOnManagementInterfaceTest { .overrideConfigKey("quarkus.management.enabled", "true"); @Test - public void testHealth() { + void testHealth() { try { RestAssured.defaultParser = Parser.JSON; when().get("http://0.0.0.0:9001/q/health/live").then() .body("status", is("UP"), "checks.status", contains("UP"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); when().get("http://0.0.0.0:9001/q/health/live").then() .body("status", is("DOWN"), "checks.status", contains("DOWN"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); } finally { RestAssured.reset(); } @@ -44,11 +44,11 @@ public void testHealth() { @Liveness static class MyCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("my-check").build(); } return HealthCheckResponse.builder().up().name("my-check").build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest.java index eac5c437bcc6e..6a7be83a02d5a 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest.java @@ -2,9 +2,10 @@ import static io.restassured.RestAssured.when; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import java.util.concurrent.atomic.AtomicInteger; + import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Liveness; @@ -15,7 +16,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest { +class HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -25,17 +26,17 @@ public class HealthCheckOnManagementInterfaceWithAbsoluteRootPathTest { .overrideConfigKey("quarkus.smallrye-health.root-path", "/sante"); @Test - public void testHealth() { + void testHealth() { try { RestAssured.defaultParser = Parser.JSON; when().get("http://0.0.0.0:9001/sante/live").then() .body("status", is("UP"), "checks.status", contains("UP"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); when().get("http://0.0.0.0:9001/sante/live").then() .body("status", is("DOWN"), "checks.status", contains("DOWN"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); } finally { RestAssured.reset(); } @@ -44,11 +45,11 @@ public void testHealth() { @Liveness static class MyCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("my-check").build(); } return HealthCheckResponse.builder().up().name("my-check").build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithRelativeRootPathTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithRelativeRootPathTest.java index 24143522a39bd..b97dadba90489 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithRelativeRootPathTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckOnManagementInterfaceWithRelativeRootPathTest.java @@ -2,9 +2,10 @@ import static io.restassured.RestAssured.when; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import java.util.concurrent.atomic.AtomicInteger; + import org.eclipse.microprofile.health.HealthCheck; import org.eclipse.microprofile.health.HealthCheckResponse; import org.eclipse.microprofile.health.Liveness; @@ -15,7 +16,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckOnManagementInterfaceWithRelativeRootPathTest { +class HealthCheckOnManagementInterfaceWithRelativeRootPathTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -26,17 +27,17 @@ public class HealthCheckOnManagementInterfaceWithRelativeRootPathTest { .overrideConfigKey("quarkus.smallrye-health.root-path", "sante"); @Test - public void testHealth() { + void testHealth() { try { RestAssured.defaultParser = Parser.JSON; when().get("http://0.0.0.0:9001/management/sante/live").then() .body("status", is("UP"), "checks.status", contains("UP"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); when().get("http://0.0.0.0:9001/management/sante/live").then() .body("status", is("DOWN"), "checks.status", contains("DOWN"), - "checks.name", containsInAnyOrder("my-check")); + "checks.name", contains("my-check")); } finally { RestAssured.reset(); } @@ -45,11 +46,11 @@ public void testHealth() { @Liveness static class MyCheck implements HealthCheck { - volatile int counter = 0; + final AtomicInteger counter = new AtomicInteger(0); @Override public HealthCheckResponse call() { - if (++counter > 1) { + if (counter.incrementAndGet() > 1) { return HealthCheckResponse.builder().down().name("my-check").build(); } return HealthCheckResponse.builder().up().name("my-check").build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckProducerDefaultScopeTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckProducerDefaultScopeTest.java index dadbfee2acc6c..4233aa75967f1 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckProducerDefaultScopeTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthCheckProducerDefaultScopeTest.java @@ -1,8 +1,7 @@ package io.quarkus.smallrye.health.test; import static io.restassured.RestAssured.when; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; import java.util.concurrent.atomic.AtomicInteger; @@ -19,7 +18,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthCheckProducerDefaultScopeTest { +class HealthCheckProducerDefaultScopeTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -27,18 +26,18 @@ public class HealthCheckProducerDefaultScopeTest { .addClasses(HealthCheckProducers.class)); @Test - public void testHealth() { + void testHealth() { // the health check does not set a content type, so we need to force the parser try { RestAssured.defaultParser = Parser.JSON; when().get("/q/health/ready").then() .body("status", is("UP"), - "checks.status", contains("UP", "UP"), - "checks.name", containsInAnyOrder("alpha1", "bravo1")); + "checks.status", hasItems("UP", "UP"), + "checks.name", hasItems("alpha1", "bravo1")); when().get("/q/health/ready").then() .body("status", is("UP"), - "checks.status", contains("UP", "UP"), - "checks.name", containsInAnyOrder("alpha1", "bravo2")); + "checks.status", hasItems("UP", "UP"), + "checks.name", hasItems("alpha1", "bravo2")); } finally { RestAssured.reset(); } @@ -51,6 +50,7 @@ static class HealthCheckProducers { // No scope - @Singleton is used by default @Readiness + @SuppressWarnings("unused") HealthCheck alpha() { int idx = ALPHA_COUNTER.incrementAndGet(); return () -> HealthCheckResponse.builder().up().name("alpha" + idx).build(); @@ -58,6 +58,7 @@ HealthCheck alpha() { @RequestScoped @Readiness + @SuppressWarnings("unused") HealthCheck bravo() { int idx = BRAVO_COUNTER.incrementAndGet(); return () -> HealthCheckResponse.builder().up().name("bravo" + idx).build(); diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthOpenAPITest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthOpenAPITest.java index dd69013e68ddd..b0b33b1ccc189 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthOpenAPITest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthOpenAPITest.java @@ -9,7 +9,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class HealthOpenAPITest { +class HealthOpenAPITest { private static final String OPEN_API_PATH = "/q/openapi"; @@ -22,7 +22,7 @@ public class HealthOpenAPITest { .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); @Test - public void testOpenApiPathAccessResource() { + void testOpenApiPathAccessResource() { RestAssured.given().header("Accept", "application/json") .when().get(OPEN_API_PATH) diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthUnitTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthUnitTest.java index a5a4a42002b52..6fa2b86c6010b 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthUnitTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/HealthUnitTest.java @@ -11,7 +11,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class HealthUnitTest { +class HealthUnitTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -20,7 +20,7 @@ public class HealthUnitTest { .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")); @Test - public void testHealth() { + void testHealth() { // the health check does not set a content type, so we need to force the parser try { RestAssured.defaultParser = Parser.JSON; diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/MaxHealthGroupTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/MaxHealthGroupTest.java index 7074da671b85d..1e953008b4fed 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/MaxHealthGroupTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/MaxHealthGroupTest.java @@ -11,7 +11,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class MaxHealthGroupTest { +class MaxHealthGroupTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -21,7 +21,7 @@ public class MaxHealthGroupTest { .overrideConfigKey("quarkus.smallrye-health.max-group-registries-count", "3"); @Test - public void testMaxGroupRegistriesCreations() { + void testMaxGroupRegistriesCreations() { try { RestAssured.defaultParser = Parser.JSON; diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/OpenApiRoute.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/OpenApiRoute.java index 767f16857a147..851f702d1454a 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/OpenApiRoute.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/OpenApiRoute.java @@ -11,7 +11,7 @@ */ @ApplicationScoped @RouteBase(path = "resource", consumes = "application/json", produces = "application/json") -public class OpenApiRoute { +class OpenApiRoute { @Route(path = "/", methods = HttpMethod.GET) public String root() { diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ShutdownReadinessCheckTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ShutdownReadinessCheckTest.java new file mode 100644 index 0000000000000..6b07b8f1b6266 --- /dev/null +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ShutdownReadinessCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.smallrye.health.test; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; +import io.restassured.parsing.Parser; + +class ShutdownReadinessCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.shutdown.delay-enabled", "true"); + + @Test + void testShutdownHealthCheckInclusion() { + try { + RestAssured.defaultParser = Parser.JSON; + RestAssured.when().get("/q/health/ready").then() + .body("status", is("UP"), + "checks.size()", is(1), + "checks.status", contains("UP"), + "checks.name", contains("Graceful Shutdown")); + } finally { + RestAssured.reset(); + } + } +} diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/StartedHealthCheckTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/StartedHealthCheckTest.java index 01008c1f9b3f3..603b11065a54a 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/StartedHealthCheckTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/StartedHealthCheckTest.java @@ -14,7 +14,7 @@ import io.restassured.RestAssured; import io.restassured.parsing.Parser; -public class StartedHealthCheckTest { +class StartedHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -22,7 +22,7 @@ public class StartedHealthCheckTest { .addClasses(StartupHC.class)); @Test - public void testStartup() { + void testStartup() { try { RestAssured.defaultParser = Parser.JSON; when().get("/q/health/started").then() diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/WellnessHealthCheckTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/WellnessHealthCheckTest.java index a138ceb7caaa3..04f6d99dfc457 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/WellnessHealthCheckTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/WellnessHealthCheckTest.java @@ -14,7 +14,7 @@ import io.restassured.parsing.Parser; import io.smallrye.health.api.Wellness; -public class WellnessHealthCheckTest { +class WellnessHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -22,7 +22,7 @@ public class WellnessHealthCheckTest { .addClasses(WellnessHC.class)); @Test - public void testWellness() { + void testWellness() { try { RestAssured.defaultParser = Parser.JSON; when().get("/q/health/well").then() diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/CustomConfigTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/CustomConfigTest.java index 2e4ccba0698af..2e5e9206e187d 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/CustomConfigTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/CustomConfigTest.java @@ -9,7 +9,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class CustomConfigTest { +class CustomConfigTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -17,7 +17,7 @@ public class CustomConfigTest { .addAsResource(new StringAsset("quarkus.smallrye-health.ui.root-path=/custom"), "application.properties")); @Test - public void shouldUseCustomConfig() { + void shouldUseCustomConfig() { RestAssured.when().get("/custom").then().statusCode(200).body(containsString("SmallRye Health")); RestAssured.when().get("/custom/index.html").then().statusCode(200).body(containsString("SmallRye Health")); } diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/DisabledTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/DisabledTest.java index 8084e6a57b3f7..34d7967cef11d 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/DisabledTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/DisabledTest.java @@ -7,7 +7,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DisabledTest { +class DisabledTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -15,7 +15,7 @@ public class DisabledTest { .addAsResource(new StringAsset("quarkus.smallrye-health.ui.enable=false"), "application.properties")); @Test - public void shouldUseDefaultConfig() { + void shouldUseDefaultConfig() { RestAssured.when().get("/q/health-ui").then().statusCode(404); } } diff --git a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/ErroneousConfigTest.java b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/ErroneousConfigTest.java index 5feda164a5220..65956e9050253 100644 --- a/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/ErroneousConfigTest.java +++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/ui/ErroneousConfigTest.java @@ -8,7 +8,7 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class ErroneousConfigTest { +class ErroneousConfigTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -17,7 +17,7 @@ public class ErroneousConfigTest { .addAsResource(new StringAsset("quarkus.smallrye-health.ui.root-path=/\n"), "application.properties")); @Test - public void shouldNotStartApplicationIfUIPathIsASlash() { + void shouldNotStartApplicationIfUIPathIsASlash() { Assertions.fail(); } } diff --git a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/ShutdownReadinessListener.java b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/ShutdownReadinessListener.java index 3a012853908b0..073416138fcda 100644 --- a/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/ShutdownReadinessListener.java +++ b/extensions/smallrye-health/runtime/src/main/java/io/quarkus/smallrye/health/runtime/ShutdownReadinessListener.java @@ -8,21 +8,18 @@ import io.quarkus.runtime.shutdown.ShutdownListener; /** - * listener that changes the readiness probe on pre-shudown + * listener that changes the readiness probe on pre-shutdown. * * Note that unless there is another preShutdown listener present * this will generally have no real effect, as after pre-shutdown * the HTTP endpoint will return service unavailable. - * - * TODO: We may want a timeout here, so the readiness probe will be down for a set timeout before shutdown continues */ public class ShutdownReadinessListener implements ShutdownListener { - @Override public void preShutdown(ShutdownNotification notification) { Instance instance = CDI.current().select(ShutdownReadinessCheck.class, Readiness.Literal.INSTANCE); - if (!instance.isUnsatisfied()) { + if (instance.isResolvable()) { instance.get().shutdown(); } notification.done();