You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2022/10/21 06:59:14 UTC
[camel] branch main updated: CAMEL-18617: Some health checks are hidden when running withg supervised controller enabled
This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 41e5c11c750 CAMEL-18617: Some health checks are hidden when running withg supervised controller enabled
41e5c11c750 is described below
commit 41e5c11c750302ebfc3d75df43459a2d62d18b35
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Thu Oct 20 12:11:35 2022 +0200
CAMEL-18617: Some health checks are hidden when running withg supervised controller enabled
---
.../main/camel-main-configuration-metadata.json | 1 +
.../camel/health-check/camel-kafka-repository | 2 -
.../camel/component/kafka/KafkaConsumer.java | 10 +-
.../camel/component/kafka/KafkaProducer.java | 10 +-
.../CamelMicroProfileHealthCheckRegistry.java | 52 ++++++---
.../CamelMicroProfileHealthComponentsTest.java | 85 ++++++++++++++
...MicroProfileHealthSupervisedRoutesMainTest.java | 15 ++-
.../health/CamelMicroProfileHealthTestHelper.java | 125 +++++++++++++++++++++
.../health/CamelMicroProfileHealthTestSupport.java | 18 +++
...thCheckRepository.java => HasHealthChecks.java} | 29 +----
.../apache/camel/health/HealthCheckRepository.java | 8 +-
.../health/WritableHealthCheckRepository.java | 33 ++++++
.../camel/health-check/components-repository | 2 +
.../health/ComponentsHealthCheckRepository.java | 27 +++--
.../HealthConfigurationPropertiesConfigurer.java | 6 +
.../camel-main-configuration-metadata.json | 1 +
core/camel-main/src/main/docs/main.adoc | 3 +-
.../org/apache/camel/main/BaseMainSupport.java | 11 ++
.../camel/main/HealthConfigurationProperties.java | 13 +++
19 files changed, 376 insertions(+), 75 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index da0c1336d03..5a9342a6808 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -143,6 +143,7 @@
{ "name": "camel.faulttolerance.timeoutEnabled", "description": "Whether timeout is enabled or not on the circuit breaker. Default is false.", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false },
{ "name": "camel.faulttolerance.timeoutPoolSize", "description": "Configures the pool size of the thread pool when timeout is enabled. Default value is 10.", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 10 },
{ "name": "camel.faulttolerance.timeoutScheduledExecutorService", "description": "References to a custom thread pool to use when timeout is enabled", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
+ { "name": "camel.health.componentsEnabled", "description": "Whether components health check is enabled", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.consumersEnabled", "description": "Whether consumers health check is enabled", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.enabled", "description": "Whether health check is enabled globally", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.excludePattern", "description": "Pattern to exclude health checks from being invoked by Camel when checking healths. Multiple patterns can be separated by comma.", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
diff --git a/components/camel-kafka/src/generated/resources/META-INF/services/org/apache/camel/health-check/camel-kafka-repository b/components/camel-kafka/src/generated/resources/META-INF/services/org/apache/camel/health-check/camel-kafka-repository
deleted file mode 100644
index 911c92477fe..00000000000
--- a/components/camel-kafka/src/generated/resources/META-INF/services/org/apache/camel/health-check/camel-kafka-repository
+++ /dev/null
@@ -1,2 +0,0 @@
-# Generated by camel build tools - do NOT edit this file!
-class=org.apache.camel.component.kafka.KafkaHealthCheckRepository
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
index 3a6d2860329..e1e29660b5c 100644
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
+++ b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
@@ -30,6 +30,7 @@ import org.apache.camel.Suspendable;
import org.apache.camel.component.kafka.consumer.errorhandler.KafkaConsumerListener;
import org.apache.camel.health.HealthCheckAware;
import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.WritableHealthCheckRepository;
import org.apache.camel.resume.ConsumerListenerAware;
import org.apache.camel.resume.ResumeAware;
import org.apache.camel.resume.ResumeStrategy;
@@ -52,7 +53,7 @@ public class KafkaConsumer extends DefaultConsumer
protected ExecutorService executor;
private final KafkaEndpoint endpoint;
private KafkaConsumerHealthCheck consumerHealthCheck;
- private KafkaHealthCheckRepository healthCheckRepository;
+ private WritableHealthCheckRepository healthCheckRepository;
// This list helps to work around the infinite loop of KAFKA-1894
private final List<KafkaFetchRecords> tasks = new ArrayList<>();
private volatile boolean stopOffsetRepo;
@@ -123,8 +124,11 @@ public class KafkaConsumer extends DefaultConsumer
super.doStart();
// health-check is optional so discover and resolve
- healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(endpoint.getCamelContext(), "camel-kafka",
- KafkaHealthCheckRepository.class);
+ healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(
+ endpoint.getCamelContext(),
+ "components",
+ WritableHealthCheckRepository.class);
+
if (healthCheckRepository != null) {
consumerHealthCheck = new KafkaConsumerHealthCheck(this, getRouteId());
healthCheckRepository.addHealthCheck(consumerHealthCheck);
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaProducer.java b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaProducer.java
index 686c422da57..78b9e062ab2 100755
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaProducer.java
+++ b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaProducer.java
@@ -38,6 +38,7 @@ import org.apache.camel.component.kafka.producer.support.ProducerUtil;
import org.apache.camel.component.kafka.producer.support.PropagatedHeadersProvider;
import org.apache.camel.component.kafka.serde.KafkaHeaderSerializer;
import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.WritableHealthCheckRepository;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.support.DefaultAsyncProducer;
import org.apache.camel.support.SynchronizationAdapter;
@@ -66,7 +67,7 @@ public class KafkaProducer extends DefaultAsyncProducer {
@SuppressWarnings("rawtypes")
private org.apache.kafka.clients.producer.Producer kafkaProducer;
private KafkaProducerHealthCheck producerHealthCheck;
- private KafkaHealthCheckRepository healthCheckRepository;
+ private WritableHealthCheckRepository healthCheckRepository;
private String clientId;
private String transactionId;
private final KafkaEndpoint endpoint;
@@ -188,8 +189,11 @@ public class KafkaProducer extends DefaultAsyncProducer {
}
// health-check is optional so discover and resolve
- healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(endpoint.getCamelContext(), "camel-kafka",
- KafkaHealthCheckRepository.class);
+ healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(
+ endpoint.getCamelContext(),
+ "components",
+ WritableHealthCheckRepository.class);
+
if (healthCheckRepository != null) {
producerHealthCheck = new KafkaProducerHealthCheck(this, clientId);
healthCheckRepository.addHealthCheck(producerHealthCheck);
diff --git a/components/camel-microprofile/camel-microprofile-health/src/main/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRegistry.java b/components/camel-microprofile/camel-microprofile-health/src/main/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRegistry.java
index b339d57d978..82d158ad561 100644
--- a/components/camel-microprofile/camel-microprofile-health/src/main/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRegistry.java
+++ b/components/camel-microprofile/camel-microprofile-health/src/main/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRegistry.java
@@ -27,6 +27,7 @@ import org.apache.camel.StartupListener;
import org.apache.camel.health.HealthCheck;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.health.HealthCheckRepository;
+import org.apache.camel.impl.health.ComponentsHealthCheckRepository;
import org.apache.camel.impl.health.ConsumersHealthCheckRepository;
import org.apache.camel.impl.health.DefaultHealthCheckRegistry;
import org.apache.camel.impl.health.HealthCheckRegistryRepository;
@@ -89,7 +90,8 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
boolean isAllChecksLiveness = repository.stream().allMatch(HealthCheck::isLiveness);
boolean isAllChecksReadiness = repository.stream().allMatch(HealthCheck::isReadiness);
- if (!(repository instanceof HealthCheckRegistryRepository) && (isAllChecksLiveness || isAllChecksReadiness)) {
+ if (!(repository instanceof HealthCheckRegistryRepository)
+ && (isAllChecksLiveness || isAllChecksReadiness)) {
try {
if (isAllChecksLiveness) {
getLivenessRegistry().remove(repository.getId());
@@ -100,7 +102,8 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
}
} catch (IllegalStateException e) {
if (LOG.isDebugEnabled()) {
- LOG.debug("Failed to remove repository readiness health {} check due to: {}", repository.getId(),
+ LOG.debug("Failed to remove repository readiness health {} check due to: {}",
+ repository.getId(),
e.getMessage());
}
}
@@ -113,12 +116,13 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
@Override
public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception {
- //Noop
+ // Noop
}
@Override
public void onCamelContextFullyStarted(CamelContext context, boolean alreadyStarted) throws Exception {
- // Some repository checks may not be resolvable earlier in the lifecycle, so try one last time on CamelContext started
+ // Some repository checks may not be resolvable earlier in the lifecycle, so try
+ // one last time on CamelContext started
if (alreadyStarted) {
repositories.stream()
.filter(repository -> repository.stream().findAny().isPresent())
@@ -133,26 +137,32 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
boolean isAllChecksReadiness = repository.stream().allMatch(HealthCheck::isReadiness);
if (repository instanceof HealthCheckRegistryRepository || !isAllChecksLiveness && !isAllChecksReadiness) {
- // Register each check individually for HealthCheckRegistryRepository or where the repository contains
+ // Register each check individually for HealthCheckRegistryRepository or where
+ // the repository contains
// a mix or readiness and liveness checks
repository.stream()
.filter(HealthCheck::isEnabled)
.forEach(this::registerMicroProfileHealthCheck);
} else {
- // Since the number of potential checks for consumers / routes etc is non-deterministic
- // avoid registering each one with SmallRye health and instead aggregate the results so
+ // Since the number of potential checks for consumers / routes etc is
+ // non-deterministic
+ // avoid registering each one with SmallRye health and instead aggregate the
+ // results so
// that we avoid highly verbose health output
String healthCheckName = repository.getId();
- if (repository.getClass().getName().startsWith("org.apache.camel") && !healthCheckName.startsWith("camel-")) {
+ if (repository.getClass().getName().startsWith("org.apache.camel")
+ && !healthCheckName.startsWith("camel-")) {
healthCheckName = "camel-" + healthCheckName;
}
- CamelMicroProfileRepositoryHealthCheck repositoryHealthCheck
- = new CamelMicroProfileRepositoryHealthCheck(getCamelContext(), repository, healthCheckName);
+ CamelMicroProfileRepositoryHealthCheck repositoryHealthCheck = new CamelMicroProfileRepositoryHealthCheck(
+ getCamelContext(), repository, healthCheckName);
- if (repository instanceof RoutesHealthCheckRepository || repository instanceof ConsumersHealthCheckRepository) {
- // Eagerly register routes & consumers HealthCheckRepository since routes may be supervised
- // and added with an initial delay. E.g repository.stream() may be empty initially but will eventually
+ if (registerEagerly(repository)) {
+ // Eagerly register routes, components & consumers HealthCheckRepository since
+ // routes may be supervised
+ // and added with an initial delay. E.g repository.stream() may be empty
+ // initially but will eventually
// return some results
getReadinessRegistry().register(repository.getId(), repositoryHealthCheck);
} else {
@@ -169,8 +179,8 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
}
protected void registerMicroProfileHealthCheck(HealthCheck camelHealthCheck) {
- org.eclipse.microprofile.health.HealthCheck microProfileHealthCheck
- = new CamelMicroProfileHealthCheck(getCamelContext(), camelHealthCheck);
+ org.eclipse.microprofile.health.HealthCheck microProfileHealthCheck = new CamelMicroProfileHealthCheck(
+ getCamelContext(), camelHealthCheck);
if (camelHealthCheck.isReadiness()) {
getReadinessRegistry().register(camelHealthCheck.getId(), microProfileHealthCheck);
@@ -204,8 +214,16 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi
}
protected boolean canRegister(HealthCheckRepository repository) {
- return repository instanceof RoutesHealthCheckRepository || repository instanceof ConsumersHealthCheckRepository
- || repository.stream().findAny().isPresent();
+ return repository.stream().findAny().isPresent()
+ || repository instanceof RoutesHealthCheckRepository
+ || repository instanceof ConsumersHealthCheckRepository
+ || repository instanceof ComponentsHealthCheckRepository;
+ }
+
+ protected boolean registerEagerly(HealthCheckRepository repository) {
+ return repository instanceof RoutesHealthCheckRepository
+ || repository instanceof ConsumersHealthCheckRepository
+ || repository instanceof ComponentsHealthCheckRepository;
}
protected HealthRegistry getLivenessRegistry() {
diff --git a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthComponentsTest.java b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthComponentsTest.java
new file mode 100644
index 00000000000..2ee2c187555
--- /dev/null
+++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthComponentsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.microprofile.health;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+import io.smallrye.health.SmallRyeHealth;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckRegistry;
+import org.eclipse.microprofile.health.HealthCheckResponse.Status;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CamelMicroProfileHealthComponentsTest extends CamelMicroProfileHealthTestSupport {
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext camelContext = super.createCamelContext();
+ camelContext.addComponent("my", new CamelMicroProfileHealthTestHelper.MyComponent());
+
+ HealthCheckRegistry healthCheckRegistry = HealthCheckRegistry.get(camelContext);
+ // enable consumers health check
+ Object hc = healthCheckRegistry.resolveById("components");
+ healthCheckRegistry.register(hc);
+
+ return camelContext;
+ }
+
+ @Test
+ public void testCamelComponentRepositoryUpStatus() {
+ context.getComponent("my", CamelMicroProfileHealthTestHelper.MyComponent.class).setState(HealthCheck.State.UP);
+
+ SmallRyeHealth health = reporter.getHealth();
+
+ JsonObject healthObject = getHealthJson(health);
+ assertEquals(Status.UP.name(), healthObject.getString("status"));
+
+ JsonArray checks = healthObject.getJsonArray("checks");
+
+ assertHealthCheckOutput("camel-components", Status.UP, checks);
+ }
+
+ @Test
+ public void testCamelComponentRepositoryDownStatus() {
+ context.getComponent("my", CamelMicroProfileHealthTestHelper.MyComponent.class).setState(HealthCheck.State.DOWN);
+
+ SmallRyeHealth health = reporter.getHealth();
+
+ JsonObject healthObject = getHealthJson(health);
+ assertEquals(Status.DOWN.name(), healthObject.getString("status"));
+
+ JsonArray checks = healthObject.getJsonArray("checks");
+
+ assertHealthCheckOutput("camel-components", Status.DOWN, checks);
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("my:start").routeId("healthyRoute")
+ .setBody(constant("Hello Camel MicroProfile Health"));
+ }
+ };
+ }
+}
diff --git a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthSupervisedRoutesMainTest.java b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthSupervisedRoutesMainTest.java
index 9ea95135080..e7c240b48a2 100644
--- a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthSupervisedRoutesMainTest.java
+++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthSupervisedRoutesMainTest.java
@@ -37,18 +37,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class CamelMicroProfileHealthSupervisedRoutesMainTest {
- private SmallRyeHealthReporter reporter = new SmallRyeHealthReporter();
+ private final SmallRyeHealthReporter reporter = new SmallRyeHealthReporter();
@Test
public void testSupervisedRouteHealthChecks() throws Exception {
CamelContext context = new DefaultCamelContext();
CamelMicroProfileHealthCheckRegistry registry = new CamelMicroProfileHealthCheckRegistry(context);
+ context.addComponent("my", new CamelMicroProfileHealthTestHelper.MyComponent());
context.setExtension(HealthCheckRegistry.class, registry);
context.getRouteController().supervising();
context.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
- from("direct:start").routeId("healthyRoute")
+ from("my:start").routeId("healthyRoute")
.setBody(constant("Hello Camel MicroProfile Health"));
}
});
@@ -56,7 +57,9 @@ public class CamelMicroProfileHealthSupervisedRoutesMainTest {
SimpleMain main = new SimpleMain(context);
main.addInitialProperty("camel.health.routes-enabled", "true");
main.addInitialProperty("camel.health.consumers-enabled", "true");
+ main.addInitialProperty("camel.health.components-enabled", "true");
main.start();
+
try {
SmallRyeHealth health = reporter.getHealth();
@@ -64,7 +67,7 @@ public class CamelMicroProfileHealthSupervisedRoutesMainTest {
assertEquals(Status.UP.name(), healthObject.getString("status"));
JsonArray checks = healthObject.getJsonArray("checks");
- assertEquals(3, checks.size());
+ assertEquals(4, checks.size());
Optional<JsonObject> camelRoutesCheck = findHealthCheck("camel-routes", checks);
camelRoutesCheck.ifPresentOrElse(check -> {
@@ -75,6 +78,11 @@ public class CamelMicroProfileHealthSupervisedRoutesMainTest {
camelConsumersCheck.ifPresentOrElse(check -> {
assertEquals(Status.UP.toString(), check.getString("status"));
}, () -> fail("Expected camel-consumers check not found in health output"));
+
+ Optional<JsonObject> camelComponentsCheck = findHealthCheck("camel-components", checks);
+ camelComponentsCheck.ifPresentOrElse(check -> {
+ assertEquals(Status.UP.toString(), check.getString("status"));
+ }, () -> fail("Expected camel-components check not found in health output"));
} finally {
main.stop();
}
@@ -86,5 +94,4 @@ public class CamelMicroProfileHealthSupervisedRoutesMainTest {
.filter(jsonObject -> jsonObject.getString("name").equals(name))
.findFirst();
}
-
}
diff --git a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestHelper.java b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestHelper.java
index f36562eb71f..70f02eb80d3 100644
--- a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestHelper.java
+++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestHelper.java
@@ -19,14 +19,30 @@ package org.apache.camel.microprofile.health;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
+import java.util.Map;
import java.util.function.Consumer;
import javax.json.Json;
+import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.stream.JsonParser;
import io.smallrye.health.SmallRyeHealth;
import io.smallrye.health.SmallRyeHealthReporter;
+import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.HealthCheckResultBuilder;
+import org.apache.camel.impl.health.AbstractHealthCheck;
+import org.apache.camel.impl.health.ComponentsHealthCheckRepository;
+import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.support.DefaultConsumer;
+import org.apache.camel.support.DefaultEndpoint;
+import org.apache.camel.support.DefaultProducer;
import org.eclipse.microprofile.health.HealthCheckResponse;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -45,6 +61,13 @@ public final class CamelMicroProfileHealthTestHelper {
assertHealthCheckOutput(expectedName, expectedState, healthObject, null);
}
+ public static void assertHealthCheckOutput(
+ String expectedName,
+ HealthCheckResponse.Status expectedState,
+ JsonArray healthObjects) {
+ assertHealthCheckOutput(expectedName, expectedState, healthObjects, null);
+ }
+
public static void assertHealthCheckOutput(
String expectedName,
HealthCheckResponse.Status expectedState,
@@ -59,6 +82,31 @@ public final class CamelMicroProfileHealthTestHelper {
}
}
+ public static void assertHealthCheckOutput(
+ String expectedName,
+ HealthCheckResponse.Status expectedState,
+ JsonArray healthObjects,
+ Consumer<JsonObject> dataObjectAssertions) {
+
+ boolean match = false;
+
+ for (int i = 0; i < healthObjects.size(); i++) {
+ JsonObject healthObject = healthObjects.getJsonObject(i);
+
+ if (expectedName.equals(healthObject.getString("name"))) {
+ match = true;
+
+ assertEquals(expectedState.name(), healthObject.getString("status"));
+
+ if (dataObjectAssertions != null) {
+ dataObjectAssertions.accept(healthObject.getJsonObject("data"));
+ }
+ }
+ }
+
+ assertTrue(match, "No elements with name " + expectedName);
+ }
+
public static JsonObject getHealthJson(SmallRyeHealthReporter reporter, SmallRyeHealth health) {
JsonParser parser = Json.createParser(new StringReader(getHealthOutput(reporter, health)));
assertTrue(parser.hasNext(), "Health check content is empty");
@@ -75,4 +123,81 @@ public final class CamelMicroProfileHealthTestHelper {
public static void dumpHealth(SmallRyeHealthReporter reporter, SmallRyeHealth health) {
reporter.reportHealth(System.out, health);
}
+
+ public static class MyComponent extends DefaultComponent {
+ private final MyHealthCheck check = new MyHealthCheck("my-hc");
+
+ @Override
+ protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+ return new MyEndpoint(uri, this, check);
+ }
+
+ public void setState(HealthCheck.State state) {
+ check.setState(state);
+ }
+ }
+
+ public static class MyEndpoint extends DefaultEndpoint {
+ private final MyHealthCheck check;
+
+ public MyEndpoint(String endpointUri, Component component, MyHealthCheck check) {
+ super(endpointUri, component);
+
+ this.check = check;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+
+ var repo = HealthCheckHelper.getHealthCheckRepository(
+ getCamelContext(),
+ ComponentsHealthCheckRepository.REPOSITORY_ID,
+ ComponentsHealthCheckRepository.class);
+
+ if (repo != null) {
+ repo.addHealthCheck(this.check);
+ }
+ }
+
+ @Override
+ public Producer createProducer() throws Exception {
+ return new DefaultProducer(this) {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ }
+ };
+ }
+
+ @Override
+ public org.apache.camel.Consumer createConsumer(Processor processor) throws Exception {
+ return new DefaultConsumer(this, processor) {
+ };
+ }
+ }
+
+ public static class MyHealthCheck extends AbstractHealthCheck {
+ private HealthCheck.State state;
+
+ public MyHealthCheck(String id) {
+ super(id);
+
+ this.state = State.UP;
+ }
+
+ @Override
+ protected void doCall(HealthCheckResultBuilder builder, Map<String, Object> options) {
+ builder.state(state);
+ }
+
+ @Override
+ public boolean isLiveness() {
+ return false;
+ }
+
+ public void setState(HealthCheck.State state) {
+ this.state = state;
+ }
+
+ }
}
diff --git a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestSupport.java b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestSupport.java
index c27765c059c..4d2ac0d67e7 100644
--- a/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestSupport.java
+++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestSupport.java
@@ -21,6 +21,7 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
+import javax.json.JsonArray;
import javax.json.JsonObject;
import io.smallrye.health.SmallRyeHealth;
@@ -78,6 +79,13 @@ public class CamelMicroProfileHealthTestSupport extends CamelTestSupport {
CamelMicroProfileHealthTestHelper.assertHealthCheckOutput(expectedName, expectedState, healthObject);
}
+ protected void assertHealthCheckOutput(
+ String expectedName,
+ HealthCheckResponse.Status expectedState,
+ JsonArray healthObjects) {
+ CamelMicroProfileHealthTestHelper.assertHealthCheckOutput(expectedName, expectedState, healthObjects);
+ }
+
protected void assertHealthCheckOutput(
String expectedName,
HealthCheckResponse.Status expectedState,
@@ -88,6 +96,16 @@ public class CamelMicroProfileHealthTestSupport extends CamelTestSupport {
dataObjectAssertions);
}
+ protected void assertHealthCheckOutput(
+ String expectedName,
+ HealthCheckResponse.Status expectedState,
+ JsonArray healthObjects,
+ Consumer<JsonObject> dataObjectAssertions) {
+
+ CamelMicroProfileHealthTestHelper.assertHealthCheckOutput(expectedName, expectedState, healthObjects,
+ dataObjectAssertions);
+ }
+
protected JsonObject getHealthJson(SmallRyeHealth health) {
return CamelMicroProfileHealthTestHelper.getHealthJson(reporter, health);
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java b/core/camel-api/src/main/java/org/apache/camel/health/HasHealthChecks.java
similarity index 53%
copy from core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java
copy to core/camel-api/src/main/java/org/apache/camel/health/HasHealthChecks.java
index 9433e5e986a..9b0a76fdbc2 100644
--- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java
+++ b/core/camel-api/src/main/java/org/apache/camel/health/HasHealthChecks.java
@@ -16,40 +16,15 @@
*/
package org.apache.camel.health;
-import java.util.Optional;
import java.util.stream.Stream;
-import org.apache.camel.spi.HasId;
-import org.apache.camel.util.ObjectHelper;
-
/**
- * A repository for health checks.
+ * An interface to represent an object which provides {@link HealthCheck}
*/
-public interface HealthCheckRepository extends HasId {
-
- /**
- * Set if the checks associated to this repository is enabled or not.
- */
- boolean isEnabled();
-
- /**
- * Set if the checks associated to this repository is enabled or not.
- */
- void setEnabled(boolean enabled);
-
+public interface HasHealthChecks {
/**
* Returns a sequential {@code Stream} with the known {@link HealthCheck} as its source.
*/
Stream<HealthCheck> stream();
- /**
- * Returns the check identified by the given <code>id</code> if available.
- */
- default Optional<HealthCheck> getCheck(String id) {
- return stream()
- .filter(r -> ObjectHelper.equal(r.getId(), id)
- || ObjectHelper.equal(r.getId().replace("-health-check", ""), id)
- || ObjectHelper.equal(r.getId().replace("route:", ""), id))
- .findFirst();
- }
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java
index 9433e5e986a..b30e35918ee 100644
--- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java
+++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java
@@ -17,7 +17,6 @@
package org.apache.camel.health;
import java.util.Optional;
-import java.util.stream.Stream;
import org.apache.camel.spi.HasId;
import org.apache.camel.util.ObjectHelper;
@@ -25,7 +24,7 @@ import org.apache.camel.util.ObjectHelper;
/**
* A repository for health checks.
*/
-public interface HealthCheckRepository extends HasId {
+public interface HealthCheckRepository extends HasId, HasHealthChecks {
/**
* Set if the checks associated to this repository is enabled or not.
@@ -37,11 +36,6 @@ public interface HealthCheckRepository extends HasId {
*/
void setEnabled(boolean enabled);
- /**
- * Returns a sequential {@code Stream} with the known {@link HealthCheck} as its source.
- */
- Stream<HealthCheck> stream();
-
/**
* Returns the check identified by the given <code>id</code> if available.
*/
diff --git a/core/camel-api/src/main/java/org/apache/camel/health/WritableHealthCheckRepository.java b/core/camel-api/src/main/java/org/apache/camel/health/WritableHealthCheckRepository.java
new file mode 100644
index 00000000000..f3f00ee95f3
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/health/WritableHealthCheckRepository.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.health;
+
+/**
+ * An interface to represent an object which wishes to be injected with the {@link HealthCheck}
+ */
+public interface WritableHealthCheckRepository extends HealthCheckRepository {
+
+ /**
+ * Adds a {@link HealthCheck} to the repository.
+ */
+ void addHealthCheck(HealthCheck healthCheck);
+
+ /**
+ * Removes a {@link HealthCheck} from the repository.
+ */
+ void removeHealthCheck(HealthCheck healthCheck);
+}
diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/components-repository b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/components-repository
new file mode 100644
index 00000000000..6dd0dfad13a
--- /dev/null
+++ b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/health-check/components-repository
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.health.ComponentsHealthCheckRepository
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaHealthCheckRepository.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/ComponentsHealthCheckRepository.java
similarity index 73%
rename from components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaHealthCheckRepository.java
rename to core/camel-health/src/main/java/org/apache/camel/impl/health/ComponentsHealthCheckRepository.java
index 7517605670a..5c80e1ec5f2 100644
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaHealthCheckRepository.java
+++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/ComponentsHealthCheckRepository.java
@@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.component.kafka;
+package org.apache.camel.impl.health;
-import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
import org.apache.camel.CamelContext;
@@ -26,22 +26,26 @@ import org.apache.camel.DeferredContextBinding;
import org.apache.camel.NonManagedService;
import org.apache.camel.StaticService;
import org.apache.camel.health.HealthCheck;
-import org.apache.camel.health.HealthCheckRepository;
+import org.apache.camel.health.WritableHealthCheckRepository;
import org.apache.camel.support.service.ServiceSupport;
/**
- * Repository for camel-kafka {@link HealthCheck}s.
+ * Repository for components {@link HealthCheck}s.
*/
-@org.apache.camel.spi.annotations.HealthCheck("camel-kafka-repository")
+@org.apache.camel.spi.annotations.HealthCheck(ComponentsHealthCheckRepository.REPOSITORY_NAME)
@DeferredContextBinding
-public class KafkaHealthCheckRepository extends ServiceSupport
- implements CamelContextAware, HealthCheckRepository, StaticService, NonManagedService {
+public class ComponentsHealthCheckRepository extends ServiceSupport
+ implements CamelContextAware, WritableHealthCheckRepository, StaticService, NonManagedService {
- private final List<HealthCheck> checks = new ArrayList<>();
+ public static final String REPOSITORY_ID = "components";
+ public static final String REPOSITORY_NAME = "components-repository";
+
+ private final List<HealthCheck> checks;
private volatile CamelContext context;
private boolean enabled = true;
- public KafkaHealthCheckRepository() {
+ public ComponentsHealthCheckRepository() {
+ this.checks = new CopyOnWriteArrayList<>();
}
@Override
@@ -51,7 +55,7 @@ public class KafkaHealthCheckRepository extends ServiceSupport
@Override
public String getId() {
- return "camel-kafka";
+ return REPOSITORY_ID;
}
@Override
@@ -76,13 +80,14 @@ public class KafkaHealthCheckRepository extends ServiceSupport
: Stream.empty();
}
+ @Override
public void addHealthCheck(HealthCheck healthCheck) {
CamelContextAware.trySetCamelContext(healthCheck, getCamelContext());
this.checks.add(healthCheck);
}
+ @Override
public void removeHealthCheck(HealthCheck healthCheck) {
this.checks.remove(healthCheck);
}
-
}
diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/HealthConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/HealthConfigurationPropertiesConfigurer.java
index 6b784e8d734..80957c1b00a 100644
--- a/core/camel-main/src/generated/java/org/apache/camel/main/HealthConfigurationPropertiesConfigurer.java
+++ b/core/camel-main/src/generated/java/org/apache/camel/main/HealthConfigurationPropertiesConfigurer.java
@@ -21,6 +21,8 @@ public class HealthConfigurationPropertiesConfigurer extends org.apache.camel.su
public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
org.apache.camel.main.HealthConfigurationProperties target = (org.apache.camel.main.HealthConfigurationProperties) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "componentsenabled":
+ case "ComponentsEnabled": target.setComponentsEnabled(property(camelContext, java.lang.Boolean.class, value)); return true;
case "consumersenabled":
case "ConsumersEnabled": target.setConsumersEnabled(property(camelContext, java.lang.Boolean.class, value)); return true;
case "enabled":
@@ -42,6 +44,8 @@ public class HealthConfigurationPropertiesConfigurer extends org.apache.camel.su
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "componentsenabled":
+ case "ComponentsEnabled": return java.lang.Boolean.class;
case "consumersenabled":
case "ConsumersEnabled": return java.lang.Boolean.class;
case "enabled":
@@ -64,6 +68,8 @@ public class HealthConfigurationPropertiesConfigurer extends org.apache.camel.su
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
org.apache.camel.main.HealthConfigurationProperties target = (org.apache.camel.main.HealthConfigurationProperties) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "componentsenabled":
+ case "ComponentsEnabled": return target.getComponentsEnabled();
case "consumersenabled":
case "ConsumersEnabled": return target.getConsumersEnabled();
case "enabled":
diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index da0c1336d03..5a9342a6808 100644
--- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -143,6 +143,7 @@
{ "name": "camel.faulttolerance.timeoutEnabled", "description": "Whether timeout is enabled or not on the circuit breaker. Default is false.", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": false },
{ "name": "camel.faulttolerance.timeoutPoolSize", "description": "Configures the pool size of the thread pool when timeout is enabled. Default value is 10.", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "integer", "javaType": "java.lang.Integer", "defaultValue": 10 },
{ "name": "camel.faulttolerance.timeoutScheduledExecutorService", "description": "References to a custom thread pool to use when timeout is enabled", "sourceType": "org.apache.camel.main.FaultToleranceConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
+ { "name": "camel.health.componentsEnabled", "description": "Whether components health check is enabled", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.consumersEnabled", "description": "Whether consumers health check is enabled", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.enabled", "description": "Whether health check is enabled globally", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "boolean", "javaType": "java.lang.Boolean", "defaultValue": true },
{ "name": "camel.health.excludePattern", "description": "Pattern to exclude health checks from being invoked by Camel when checking healths. Multiple patterns can be separated by comma.", "sourceType": "org.apache.camel.main.HealthConfigurationProperties", "type": "string", "javaType": "java.lang.String" },
diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc
index 6d9f53c533a..7a1f658290d 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -160,11 +160,12 @@ The camel.threadpool supports 8 options, which are listed below.
|===
=== Camel Health Check configurations
-The camel.health supports 7 options, which are listed below.
+The camel.health supports 8 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
+| *camel.health.componentsEnabled* | Whether components health check is enabled | true | Boolean
| *camel.health.consumersEnabled* | Whether consumers health check is enabled | true | Boolean
| *camel.health.enabled* | Whether health check is enabled globally | true | Boolean
| *camel.health.excludePattern* | Pattern to exclude health checks from being invoked by Camel when checking healths. Multiple patterns can be separated by comma. | | String
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index fc9e95f18a5..e5d6aa38f0a 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -1253,6 +1253,17 @@ public abstract class BaseMainSupport extends BaseService {
hcr.register(hc);
}
}
+ // components are enabled by default
+ if (hcr.isEnabled()) {
+ HealthCheckRepository hc
+ = hcr.getRepository("components").orElse((HealthCheckRepository) hcr.resolveById("components"));
+ if (hc != null) {
+ if (health.getComponentsEnabled() != null) {
+ hc.setEnabled(health.getComponentsEnabled());
+ }
+ hcr.register(hc);
+ }
+ }
// consumers are enabled by default
if (hcr.isEnabled()) {
HealthCheckRepository hc
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/HealthConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/HealthConfigurationProperties.java
index a188921c4b1..c8954215f24 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/HealthConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/HealthConfigurationProperties.java
@@ -35,6 +35,8 @@ public class HealthConfigurationProperties implements BootstrapCloseable {
@Metadata(defaultValue = "true")
private Boolean consumersEnabled;
@Metadata(defaultValue = "true")
+ private Boolean componentsEnabled;
+ @Metadata(defaultValue = "true")
private Boolean registryEnabled;
@Metadata
private String excludePattern;
@@ -89,6 +91,17 @@ public class HealthConfigurationProperties implements BootstrapCloseable {
this.consumersEnabled = consumersEnabled;
}
+ public Boolean getComponentsEnabled() {
+ return componentsEnabled;
+ }
+
+ /**
+ * Whether components health check is enabled
+ */
+ public void setComponentsEnabled(Boolean componentsEnabled) {
+ this.componentsEnabled = componentsEnabled;
+ }
+
public Boolean getRegistryEnabled() {
return registryEnabled;
}