diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index a2801854fbb97..fbe671d5ed3d8 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -54,7 +54,7 @@
1.0.13
2.6.0
2.11.0
- 3.7.1
+ 3.8.0
1.2.1
1.3.5
3.0.3
diff --git a/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesHealthStartupPathBuildItem.java b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesHealthStartupPathBuildItem.java
new file mode 100644
index 0000000000000..d4f962996a641
--- /dev/null
+++ b/extensions/kubernetes/spi/src/main/java/io/quarkus/kubernetes/spi/KubernetesHealthStartupPathBuildItem.java
@@ -0,0 +1,19 @@
+package io.quarkus.kubernetes.spi;
+
+import io.quarkus.builder.item.SimpleBuildItem;
+
+public final class KubernetesHealthStartupPathBuildItem extends SimpleBuildItem {
+
+ private final String path;
+
+ public KubernetesHealthStartupPathBuildItem(String path) {
+ this.path = path;
+ }
+
+ /**
+ * @return the path
+ */
+ public String getPath() {
+ return path;
+ }
+}
diff --git a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/HealthOpenAPIFilter.java b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/HealthOpenAPIFilter.java
index 96051e54fbc61..063a47ffcd6e0 100644
--- a/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/HealthOpenAPIFilter.java
+++ b/extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/HealthOpenAPIFilter.java
@@ -36,11 +36,13 @@ public class HealthOpenAPIFilter implements OASFilter {
private final String rootPath;
private final String livenessPath;
private final String readinessPath;
+ private final String startupPath;
- public HealthOpenAPIFilter(String rootPath, String livenessPath, String readinessPath) {
+ public HealthOpenAPIFilter(String rootPath, String livenessPath, String readinessPath, String startupPath) {
this.rootPath = rootPath;
this.livenessPath = livenessPath;
this.readinessPath = readinessPath;
+ this.startupPath = startupPath;
}
@Override
@@ -64,6 +66,9 @@ public void filterOpenAPI(OpenAPI openAPI) {
// Readiness
paths.addPathItem(readinessPath, createReadinessPathItem());
+
+ // Startup
+ paths.addPathItem(startupPath, createStartupPathItem());
}
private PathItem createHealthPathItem() {
@@ -93,12 +98,21 @@ private PathItem createReadinessPathItem() {
return pathItem;
}
+ private PathItem createStartupPathItem() {
+ PathItem pathItem = new PathItemImpl();
+ pathItem.setDescription("MicroProfile Health - Startup Endpoint");
+ pathItem.setSummary(
+ "Startup checks are an used to tell when the application has started");
+ pathItem.setGET(createStartupOperation());
+ return pathItem;
+ }
+
private Operation createHealthOperation() {
Operation operation = new OperationImpl();
operation.setDescription("Check the health of the application");
operation.setOperationId("microprofile_health_root");
operation.setTags(MICROPROFILE_HEALTH_TAG);
- operation.setSummary("An aggregated view of the Liveness and Readiness of this application");
+ operation.setSummary("An aggregated view of the Liveness, Readiness and Startup of this application");
operation.setResponses(createAPIResponses());
return operation;
}
@@ -123,6 +137,16 @@ private Operation createReadinessOperation() {
return operation;
}
+ private Operation createStartupOperation() {
+ Operation operation = new OperationImpl();
+ operation.setDescription("Check the startup of the application");
+ operation.setOperationId("microprofile_health_startup");
+ operation.setTags(MICROPROFILE_HEALTH_TAG);
+ operation.setSummary("The Startup check of this application");
+ operation.setResponses(createAPIResponses());
+ return operation;
+ }
+
private APIResponses createAPIResponses() {
APIResponses responses = new APIResponsesImpl();
responses.addAPIResponse("200", createAPIResponse("OK"));
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 53b004acc3cd1..b328f96324008 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
@@ -20,6 +20,7 @@
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
+import org.eclipse.microprofile.health.Startup;
import org.eclipse.microprofile.health.spi.HealthCheckResponseProvider;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
@@ -59,6 +60,7 @@
import io.quarkus.deployment.util.WebJarUtil;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
+import io.quarkus.kubernetes.spi.KubernetesHealthStartupPathBuildItem;
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
import io.quarkus.smallrye.health.runtime.ShutdownReadinessListener;
import io.quarkus.smallrye.health.runtime.SmallRyeHealthGroupHandler;
@@ -85,6 +87,7 @@ class SmallRyeHealthProcessor {
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());
private static final DotName HEALTH_GROUP = DotName.createSimple(HealthGroup.class.getName());
private static final DotName HEALTH_GROUPS = DotName.createSimple(HealthGroups.class.getName());
private static final DotName WELLNESS = DotName.createSimple(Wellness.class.getName());
@@ -154,10 +157,11 @@ void build(SmallRyeHealthRecorder recorder,
feature.produce(new FeatureBuildItem(Feature.SMALLRYE_HEALTH));
- // Discover the beans annotated with @Health, @Liveness, @Readiness, @HealthGroup,
+ // Discover the beans annotated with @Health, @Liveness, @Readiness, @Startup, @HealthGroup,
// @HealthGroups and @Wellness even if no scope is defined
beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(LIVENESS));
beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(READINESS));
+ beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(STARTUP));
beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(HEALTH_GROUP));
beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(HEALTH_GROUPS));
beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(WELLNESS));
@@ -195,6 +199,7 @@ public void defineHealthRoutes(BuildProducer routes,
// log a warning if users try to use MP Health annotations with JAX-RS @Path
warnIfJaxRsPathUsed(index, LIVENESS);
warnIfJaxRsPathUsed(index, READINESS);
+ warnIfJaxRsPathUsed(index, STARTUP);
warnIfJaxRsPathUsed(index, WELLNESS);
// Register the health handler
@@ -291,7 +296,8 @@ public void includeInOpenAPIEndpoint(BuildProducer livenessPathItemProducer,
- BuildProducer readinessPathItemProducer) {
+ BuildProducer readinessPathItemProducer,
+ BuildProducer startupPathItemProducer) {
livenessPathItemProducer.produce(
new KubernetesHealthLivenessPathBuildItem(
@@ -332,6 +339,9 @@ public void kubernetes(NonApplicationRootPathBuildItem nonApplicationRootPathBui
readinessPathItemProducer.produce(
new KubernetesHealthReadinessPathBuildItem(
nonApplicationRootPathBuildItem.resolveNestedPath(healthConfig.rootPath, healthConfig.readinessPath)));
+ startupPathItemProducer.produce(
+ new KubernetesHealthStartupPathBuildItem(
+ nonApplicationRootPathBuildItem.resolveNestedPath(healthConfig.rootPath, healthConfig.startupPath)));
}
@BuildStep
@@ -355,6 +365,7 @@ AnnotationsTransformerBuildItem annotationTransformer(BeanArchiveIndexBuildItem
List healthAnnotations = new ArrayList<>(5);
healthAnnotations.add(LIVENESS);
healthAnnotations.add(READINESS);
+ healthAnnotations.add(STARTUP);
healthAnnotations.add(HEALTH_GROUP);
healthAnnotations.add(HEALTH_GROUPS);
healthAnnotations.add(WELLNESS);
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 ab5aea1fb279a..37a33ba11ce46 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
@@ -7,6 +7,7 @@
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
+import org.eclipse.microprofile.health.Startup;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
@@ -65,6 +66,9 @@ public void testHealthCheckMetadata() {
selects = checks.select(Readiness.Literal.INSTANCE);
Assertions.assertTrue(isUnique(selects));
+ selects = checks.select(Startup.Literal.INSTANCE);
+ Assertions.assertTrue(isUnique(selects));
+
selects = checks.select(HealthGroup.Literal.of("group1"));
Assertions.assertTrue(isUnique(selects));
@@ -73,6 +77,7 @@ public void testHealthCheckMetadata() {
selects = checks.select(Liveness.Literal.INSTANCE,
Readiness.Literal.INSTANCE,
+ Startup.Literal.INSTANCE,
HealthGroup.Literal.of("group1"),
HealthGroup.Literal.of("group2"));
Assertions.assertTrue(isUnique(selects));
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 25ef0fe463d4f..3347daf5257a7 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
@@ -10,12 +10,14 @@
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
+import org.eclipse.microprofile.health.Startup;
import io.smallrye.health.api.HealthGroup;
@Dependent
@Liveness
@Readiness
+@Startup
@HealthGroup("group1")
@HealthGroup("group2")
public class FailingHealthCheck implements HealthCheck {
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 aad0dfc2ba741..544288c94be5f 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
@@ -35,6 +35,7 @@ public class FailingUnitTest {
public 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);
RestAssured.when().get("/q/health").then().statusCode(503);
}
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 912f6fe7d498b..ab9615ee53067 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
@@ -32,6 +32,7 @@ public void testOpenApiPathAccessResource() {
.header("Content-Type", "application/json;charset=UTF-8")
.body("paths", Matchers.hasKey("/q/health/ready"))
.body("paths", Matchers.hasKey("/q/health/live"))
+ .body("paths", Matchers.hasKey("/q/health/started"))
.body("paths", Matchers.hasKey("/q/health"))
.body("components.schemas.HealthCheckResponse.type", Matchers.equalTo("object"));
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
new file mode 100644
index 0000000000000..0dd0e53420b74
--- /dev/null
+++ b/extensions/smallrye-health/deployment/src/test/java/io/quarkus/smallrye/health/test/StartedHealthCheckTest.java
@@ -0,0 +1,48 @@
+package io.quarkus.smallrye.health.test;
+
+import static io.restassured.RestAssured.when;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+import org.eclipse.microprofile.health.Startup;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+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;
+
+public class StartedHealthCheckTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(StartupHC.class));
+
+ @Test
+ public void testStartup() {
+ try {
+ RestAssured.defaultParser = Parser.JSON;
+ when().get("/q/health/started").then()
+ .body("status", is("UP"),
+ "checks.status", contains("UP"),
+ "checks.name", contains(StartupHC.class.getName()));
+ } finally {
+ RestAssured.reset();
+ }
+ }
+
+ @Startup
+ static class StartupHC implements HealthCheck {
+
+ @Override
+ public HealthCheckResponse call() {
+ return HealthCheckResponse.up(StartupHC.class.getName());
+ }
+ }
+
+}
diff --git a/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/SmallRyeReactiveMessagingProcessor.java b/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/SmallRyeReactiveMessagingProcessor.java
index 539530a13aac3..6b3fb5996d6b2 100644
--- a/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/SmallRyeReactiveMessagingProcessor.java
+++ b/extensions/smallrye-reactive-messaging/deployment/src/main/java/io/quarkus/smallrye/reactivemessaging/deployment/SmallRyeReactiveMessagingProcessor.java
@@ -80,6 +80,7 @@
import io.smallrye.reactive.messaging.extension.EmitterConfiguration;
import io.smallrye.reactive.messaging.health.SmallRyeReactiveMessagingLivenessCheck;
import io.smallrye.reactive.messaging.health.SmallRyeReactiveMessagingReadinessCheck;
+import io.smallrye.reactive.messaging.health.SmallRyeReactiveMessagingStartupCheck;
public class SmallRyeReactiveMessagingProcessor {
@@ -346,6 +347,9 @@ public void enableHealth(ReactiveMessagingBuildTimeConfig buildTimeConfig,
producer.produce(
new HealthBuildItem(SmallRyeReactiveMessagingReadinessCheck.class.getName(),
buildTimeConfig.healthEnabled));
+ producer.produce(
+ new HealthBuildItem(SmallRyeReactiveMessagingStartupCheck.class.getName(),
+ buildTimeConfig.healthEnabled));
}
@BuildStep