This is an automated email from the ASF dual-hosted git repository. jamesnetherton 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 165f7cb3a25 CAMEL-18483: Fix CamelMicroProfileHealthCheckRegistry registration for routes and consumers health checks when routes are supervised 165f7cb3a25 is described below commit 165f7cb3a257b95196f8b3795f5b15c1f310c86c Author: James Netherton <jamesnether...@gmail.com> AuthorDate: Thu Sep 8 10:01:37 2022 +0100 CAMEL-18483: Fix CamelMicroProfileHealthCheckRegistry registration for routes and consumers health checks when routes are supervised --- .../camel-microprofile-health/pom.xml | 5 ++ .../CamelMicroProfileHealthCheckRegistry.java | 27 +++++-- ...MicroProfileHealthSupervisedRoutesMainTest.java | 90 ++++++++++++++++++++++ .../health/CamelMicroProfileHealthTestHelper.java | 78 +++++++++++++++++++ .../health/CamelMicroProfileHealthTestSupport.java | 34 ++------ 5 files changed, 199 insertions(+), 35 deletions(-) diff --git a/components/camel-microprofile/camel-microprofile-health/pom.xml b/components/camel-microprofile/camel-microprofile-health/pom.xml index 24c31ab8af0..6bd4462fef0 100644 --- a/components/camel-microprofile/camel-microprofile-health/pom.xml +++ b/components/camel-microprofile/camel-microprofile-health/pom.xml @@ -62,6 +62,11 @@ <artifactId>camel-test-junit5</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-main</artifactId> + <scope>test</scope> + </dependency> <!-- JSON support for smallrye-health --> <dependency> 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 84e8882857f..b339d57d978 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,8 +27,10 @@ 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.ConsumersHealthCheckRepository; import org.apache.camel.impl.health.DefaultHealthCheckRegistry; import org.apache.camel.impl.health.HealthCheckRegistryRepository; +import org.apache.camel.impl.health.RoutesHealthCheckRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +68,7 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi } } else { HealthCheckRepository repository = (HealthCheckRepository) obj; - if (repository.stream().findAny().isPresent()) { + if (canRegister(repository)) { registerRepositoryChecks(repository); } else { // Try health check registration again on CamelContext started @@ -134,7 +136,7 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi // Register each check individually for HealthCheckRegistryRepository or where the repository contains // a mix or readiness and liveness checks repository.stream() - .filter(healthCheck -> healthCheck.isEnabled()) + .filter(HealthCheck::isEnabled) .forEach(this::registerMicroProfileHealthCheck); } else { // Since the number of potential checks for consumers / routes etc is non-deterministic @@ -147,12 +149,20 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi CamelMicroProfileRepositoryHealthCheck repositoryHealthCheck = new CamelMicroProfileRepositoryHealthCheck(getCamelContext(), repository, healthCheckName); - if (isAllChecksLiveness) { - getLivenessRegistry().register(repository.getId(), repositoryHealthCheck); - } - if (isAllChecksReadiness) { + 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 + // return some results getReadinessRegistry().register(repository.getId(), repositoryHealthCheck); + } else { + if (isAllChecksLiveness) { + getLivenessRegistry().register(repository.getId(), repositoryHealthCheck); + } + + if (isAllChecksReadiness) { + getReadinessRegistry().register(repository.getId(), repositoryHealthCheck); + } } } } @@ -193,6 +203,11 @@ public class CamelMicroProfileHealthCheckRegistry extends DefaultHealthCheckRegi } } + protected boolean canRegister(HealthCheckRepository repository) { + return repository instanceof RoutesHealthCheckRepository || repository instanceof ConsumersHealthCheckRepository + || repository.stream().findAny().isPresent(); + } + protected HealthRegistry getLivenessRegistry() { return HealthRegistries.getRegistry(HealthType.LIVENESS); } 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 new file mode 100644 index 00000000000..9ea95135080 --- /dev/null +++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthSupervisedRoutesMainTest.java @@ -0,0 +1,90 @@ +/* + * 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 java.util.Optional; + +import javax.json.JsonArray; +import javax.json.JsonObject; +import javax.json.JsonValue; + +import io.smallrye.health.SmallRyeHealth; +import io.smallrye.health.SmallRyeHealthReporter; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.health.HealthCheckRegistry; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.main.SimpleMain; +import org.eclipse.microprofile.health.HealthCheckResponse.Status; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.microprofile.health.CamelMicroProfileHealthTestHelper.getHealthJson; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class CamelMicroProfileHealthSupervisedRoutesMainTest { + private SmallRyeHealthReporter reporter = new SmallRyeHealthReporter(); + + @Test + public void testSupervisedRouteHealthChecks() throws Exception { + CamelContext context = new DefaultCamelContext(); + CamelMicroProfileHealthCheckRegistry registry = new CamelMicroProfileHealthCheckRegistry(context); + context.setExtension(HealthCheckRegistry.class, registry); + context.getRouteController().supervising(); + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId("healthyRoute") + .setBody(constant("Hello Camel MicroProfile Health")); + } + }); + + SimpleMain main = new SimpleMain(context); + main.addInitialProperty("camel.health.routes-enabled", "true"); + main.addInitialProperty("camel.health.consumers-enabled", "true"); + main.start(); + try { + SmallRyeHealth health = reporter.getHealth(); + + JsonObject healthObject = getHealthJson(reporter, health); + assertEquals(Status.UP.name(), healthObject.getString("status")); + + JsonArray checks = healthObject.getJsonArray("checks"); + assertEquals(3, checks.size()); + + Optional<JsonObject> camelRoutesCheck = findHealthCheck("camel-routes", checks); + camelRoutesCheck.ifPresentOrElse(check -> { + assertEquals(Status.UP.toString(), check.getString("status")); + }, () -> fail("Expected camel-routes check not found in health output")); + + Optional<JsonObject> camelConsumersCheck = findHealthCheck("camel-consumers", checks); + camelConsumersCheck.ifPresentOrElse(check -> { + assertEquals(Status.UP.toString(), check.getString("status")); + }, () -> fail("Expected camel-consumers check not found in health output")); + } finally { + main.stop(); + } + } + + private Optional<JsonObject> findHealthCheck(String name, JsonArray checks) { + return checks.stream() + .map(JsonValue::asJsonObject) + .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 new file mode 100644 index 00000000000..f36562eb71f --- /dev/null +++ b/components/camel-microprofile/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthTestHelper.java @@ -0,0 +1,78 @@ +/* + * 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 java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.stream.JsonParser; + +import io.smallrye.health.SmallRyeHealth; +import io.smallrye.health.SmallRyeHealthReporter; +import org.eclipse.microprofile.health.HealthCheckResponse; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public final class CamelMicroProfileHealthTestHelper { + + private CamelMicroProfileHealthTestHelper() { + // Utility class + } + + public static void assertHealthCheckOutput( + String expectedName, + HealthCheckResponse.Status expectedState, + JsonObject healthObject) { + assertHealthCheckOutput(expectedName, expectedState, healthObject, null); + } + + public static void assertHealthCheckOutput( + String expectedName, + HealthCheckResponse.Status expectedState, + JsonObject healthObject, + Consumer<JsonObject> dataObjectAssertions) { + + assertEquals(expectedName, healthObject.getString("name")); + assertEquals(expectedState.name(), healthObject.getString("status")); + + if (dataObjectAssertions != null) { + dataObjectAssertions.accept(healthObject.getJsonObject("data")); + } + } + + 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"); + parser.next(); + return parser.getObject(); + } + + public static String getHealthOutput(SmallRyeHealthReporter reporter, SmallRyeHealth health) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + reporter.reportHealth(outputStream, health); + return outputStream.toString(StandardCharsets.UTF_8); + } + + public static void dumpHealth(SmallRyeHealthReporter reporter, SmallRyeHealth health) { + reporter.reportHealth(System.out, health); + } +} 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 acd9317eb34..c27765c059c 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 @@ -16,17 +16,12 @@ */ package org.apache.camel.microprofile.health; -import java.io.ByteArrayOutputStream; -import java.io.StringReader; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; -import javax.json.Json; import javax.json.JsonObject; -import javax.json.stream.JsonParser; import io.smallrye.health.SmallRyeHealth; import io.smallrye.health.SmallRyeHealthReporter; @@ -43,9 +38,6 @@ import org.apache.camel.test.junit5.CamelTestSupport; import org.eclipse.microprofile.health.HealthCheckResponse; import org.junit.jupiter.api.AfterEach; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - public class CamelMicroProfileHealthTestSupport extends CamelTestSupport { protected SmallRyeHealthReporter reporter = new SmallRyeHealthReporter(); @@ -83,7 +75,7 @@ public class CamelMicroProfileHealthTestSupport extends CamelTestSupport { String expectedName, HealthCheckResponse.Status expectedState, JsonObject healthObject) { - assertHealthCheckOutput(expectedName, expectedState, healthObject, null); + CamelMicroProfileHealthTestHelper.assertHealthCheckOutput(expectedName, expectedState, healthObject); } protected void assertHealthCheckOutput( @@ -92,25 +84,16 @@ public class CamelMicroProfileHealthTestSupport extends CamelTestSupport { JsonObject healthObject, Consumer<JsonObject> dataObjectAssertions) { - assertEquals(expectedName, healthObject.getString("name")); - assertEquals(expectedState.name(), healthObject.getString("status")); - - if (dataObjectAssertions != null) { - dataObjectAssertions.accept(healthObject.getJsonObject("data")); - } + CamelMicroProfileHealthTestHelper.assertHealthCheckOutput(expectedName, expectedState, healthObject, + dataObjectAssertions); } protected JsonObject getHealthJson(SmallRyeHealth health) { - JsonParser parser = Json.createParser(new StringReader(getHealthOutput(health))); - assertTrue(parser.hasNext(), "Health check content is empty"); - parser.next(); - return parser.getObject(); + return CamelMicroProfileHealthTestHelper.getHealthJson(reporter, health); } protected String getHealthOutput(SmallRyeHealth health) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - reporter.reportHealth(outputStream, health); - return new String(outputStream.toByteArray(), StandardCharsets.UTF_8); + return CamelMicroProfileHealthTestHelper.getHealthOutput(reporter, health); } protected HealthCheck createLivenessCheck(String id, boolean enabled, Consumer<HealthCheckResultBuilder> consumer) { @@ -144,11 +127,4 @@ public class CamelMicroProfileHealthTestSupport extends CamelTestSupport { readinessCheck.setEnabled(enabled); return readinessCheck; } - - /** - * Dump health check status to stdout, useful for debugging. - */ - protected void dumpHealth(SmallRyeHealth health) { - reporter.reportHealth(System.out, health); - } }