This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch camel-master in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit fe3c3aaead75840162b4ab7c82c52c853697352a Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Jun 10 07:06:15 2020 +0200 health example - requires Camel 3.4 (#1321) * health example - requires Camel 3.4 * Upgrade microprofile integration test to latest Camel 3.4 SNAPSHOT * Upgrade observability example test to latest Camel 3.4 SNAPSHOT --- examples/health/README.adoc | 78 ++++++++++++++++ examples/health/pom.xml | 103 +++++++++++++++++++++ .../java/org/acme/health/MonkeyHealthCheck.java | 62 +++++++++++++ .../main/java/org/acme/health/MyRouteBuilder.java | 42 +++++++++ .../src/main/resources/application.properties | 77 +++++++++++++++ .../org/acme/observability/ObservabilityTest.java | 3 +- examples/pom.xml | 1 + .../it/health/MicroProfileHealthTest.java | 9 +- 8 files changed, 370 insertions(+), 5 deletions(-) diff --git a/examples/health/README.adoc b/examples/health/README.adoc new file mode 100644 index 0000000..964c972 --- /dev/null +++ b/examples/health/README.adoc @@ -0,0 +1,78 @@ +== Camel Quarkus Example Health + +This example shows how to use Camel health-check with Quarkus. +The example shows how you can build custom health-checks and have +them automatic discovered by Camel and used as parts of its health-check system. + +TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites +and other general information. + +The example has two routes, a timer that calls a bean that flips a boolean that +causes the custom health check to be in either UP or DOWN state. + +The 2nd route is on purpose made to fail on startup by configuring netty to an unknown host. +Camel supervising route controller will attempt to restart the route up till 10 times before exhausting. + +The routes health check will therefore report this route as DOWN until its exhausted +where the states are changed to UNKNOWN. + +The details can be seen at runtime from the calling the following url from a web browser: http://localhost:8080/health + +=== Start in the Development mode + +[source,shell] +---- +$ mvn clean compile quarkus:dev +---- + +The above command compiles the project, starts the application and lets the Quarkus tooling watch for changes in your +workspace. Any modifications in your project will automatically take effect in the running application. + +TIP: Please refer to the Development mode section of +https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode[Camel Quarkus User guide] for more details. + +You can check the health check status by calling the following url from a web browser: http://localhost:8080/health + +=== Package and run the application + +Once you are done with developing you may want to package and run the application. + +TIP: Find more details about the JVM mode and Native mode in the Package and run section of +https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide] + +=== JVM mode + +[source,shell] +---- +$ mvn clean package +$ java -jar target/*-runner.jar +... +[io.quarkus] (main) Quarkus 1.3.2 started in 1.163s. Listening on: http://[::]:8080 +---- + +=== Native mode + +IMPORTANT: Native mode requires having GraalVM and other tools installed. Please check the Prerequisites section +of https://camel.apache.org/camel-quarkus/latest/first-steps.html#_prerequisites[Camel Quarkus User guide]. + +To prepare a native executable using GraalVM, run the following command: + +[source,shell] +---- +$ mvn clean package -Pnative +$ ./target/*-runner +... +[io.quarkus] (main) Quarkus 1.3.2 started in 0.013s. Listening on: http://[::]:8080 +... +---- + +=== Help and contributions + +If you hit any problem using Camel or have some feedback, then please +https://camel.apache.org/support.html[let us know]. + +We also love contributors, so +https://camel.apache.org/contributing.html[get involved] :-) + +The Camel riders! + diff --git a/examples/health/pom.xml b/examples/health/pom.xml new file mode 100644 index 0000000..52be628 --- /dev/null +++ b/examples/health/pom.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-build-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../../poms/build-parent/pom.xml</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + + <artifactId>camel-quarkus-examples-health</artifactId> + <name>Camel Quarkus :: Examples :: Health</name> + <description>Camel Quarkus Example :: Health Check</description> + + <properties> + <!-- mvnd, a.k.a. Maven Daemon: https://github.com/gnodet/mvnd --> + <!-- The following rule tells mvnd to build the listed deployment modules before this module. --> + <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not --> + <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. --> + <!-- Please update rule whenever you change the dependencies of this module by running --> + <!-- mvn process-resources -Pformat from the root directory --> + <mvnd.builder.rule>camel-quarkus-log-deployment,camel-quarkus-support-policy-deployment,camel-quarkus-timer-deployment</mvnd.builder.rule> + </properties> + + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bean</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-log</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-netty</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-timer</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-microprofile-health</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <executions> + <execution> + <id>build</id> + <goals> + <goal>build</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>native</id> + <activation> + <property> + <name>native</name> + </property> + </activation> + <properties> + <quarkus.package.type>native</quarkus.package.type> + </properties> + </profile> + </profiles> + +</project> diff --git a/examples/health/src/main/java/org/acme/health/MonkeyHealthCheck.java b/examples/health/src/main/java/org/acme/health/MonkeyHealthCheck.java new file mode 100644 index 0000000..479d60c --- /dev/null +++ b/examples/health/src/main/java/org/acme/health/MonkeyHealthCheck.java @@ -0,0 +1,62 @@ +/* + * 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.acme.health; + +import java.util.Map; + +import javax.enterprise.context.ApplicationScoped; + +import org.apache.camel.health.HealthCheckResultBuilder; +import org.apache.camel.impl.health.AbstractHealthCheck; + +/** + * A chaos monkey health check that reports UP or DOWN in a chaotic way. + * + * This is a custom implementation of a Camel {@link org.apache.camel.health.HealthCheck} + * which is automatic discovered if bound in the {@link org.apache.camel.spi.Registry} and + * used as part of Camel's health-check system. + */ +@ApplicationScoped +public class MonkeyHealthCheck extends AbstractHealthCheck { + + private boolean up = true; + + public MonkeyHealthCheck() { + super("custom", "monkey"); + } + + @Override + protected void doCall(HealthCheckResultBuilder builder, Map<String, Object> options) { + builder.detail("monkey", "The chaos monkey was here"); + if (up) { + builder.up(); + } else { + builder.down(); + } + } + + public String chaos() { + up = !up; + return up ? "All is okay" : "Chaos monkey was here"; + } + + @Override + public boolean isReadiness() { + // only liveness probe + return false; + } +} diff --git a/examples/health/src/main/java/org/acme/health/MyRouteBuilder.java b/examples/health/src/main/java/org/acme/health/MyRouteBuilder.java new file mode 100644 index 0000000..88288db --- /dev/null +++ b/examples/health/src/main/java/org/acme/health/MyRouteBuilder.java @@ -0,0 +1,42 @@ +/* + * 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.acme.health; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.apache.camel.builder.RouteBuilder; + +@ApplicationScoped +public class MyRouteBuilder extends RouteBuilder { + + // we can inject the bean via this annotation + @Inject + MonkeyHealthCheck monkey; + + @Override + public void configure() throws Exception { + from("timer:foo?period={{myPeriod}}").routeId("timer") + .bean(monkey, "chaos") + .log("${body}"); + + // this route is invalid and fails during startup + // the supervising route controller will take over and attempt + // to restart this route + from("netty:tcp:unknownhost").to("log:dummy").routeId("netty"); + } +} diff --git a/examples/health/src/main/resources/application.properties b/examples/health/src/main/resources/application.properties new file mode 100644 index 0000000..f6ab0d7 --- /dev/null +++ b/examples/health/src/main/resources/application.properties @@ -0,0 +1,77 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +# +# Quarkus +# +quarkus.banner.enabled = false + +# to configure camel main +# here you can configure options on camel quarkus +camel.quakus.name = MyHealthyCamel + +# extended runtime statistics about bean introspection usage (java reflection) +camel.main.bean-introspection-extended-statistics=true +camel.main.bean-introspection-logging-level=INFO + +# enable supervised route controller which will startup routes in safe manner +camel.main.route-controller-supervise-enabled = true +# attempt up till 10 times to start a route (and exhaust if still failing) +# when a route is exhausted then its taken out as being supervised and +# will not take part of health-check either (UNKNOWN state) +camel.main.route-controller-back-off-max-attempts = 10 +# when starting a route (and restarts) fails all attempts +# then we can control whether the route should be influence the health-check +# and report the route as either UNKNOWN or DOWN. Setting this option to true +# will report it as DOWN otherwise its UNKNOWN +###camel.main.route-controller-unhealthy-on-exhausted = true + +# enable health check (is automatic enabled if discovered on classpath) +# global flag to enable/disable +camel.health.enabled = true +# context check is default included but we can turn it on|off +camel.health.context-enabled = true +# routes check is default included but we can turn it on|off +camel.health.routes-enabled = true +# registry check is default included but we can turn it on|off +camel.health.registry-enabled = true + +# you can turn on or off individual routes as shown below +### camel.heath.config[timer].parent = routes +### camel.heath.config[timer].enabled = true +### camel.heath.config[netty].check = routes +### camel.heath.config[netty].enabled = false + +# and configure each individually +camel.health.config[timer].parent = routes +camel.health.config[timer].interval = 5s +camel.health.config[netty].parent = routes +camel.health.config[netty].interval = 20s +camel.health.config[netty].failure-threshold = 10 + +# find grained routes configuration per route (support wildcards) +# (enabled is default true for discovered health-checks) +### camel.health.config[*].enabled = true + +# allow 5 failures with 10s apart as slack to handle routes being flaky +# however if after 5 failures then the state will be regarded as DOWN onwards +# (the route can recover and the state will then be UP) +###camel.health.config[*].parent = routes +###camel.health.config[*].interval = 10s +###camel.health.config[*].failure-threshold = 5 + +# properties used in the route +myPeriod = 10s diff --git a/examples/observability/src/test/java/org/acme/observability/ObservabilityTest.java b/examples/observability/src/test/java/org/acme/observability/ObservabilityTest.java index 4ebfc9e..d9a4d3c 100644 --- a/examples/observability/src/test/java/org/acme/observability/ObservabilityTest.java +++ b/examples/observability/src/test/java/org/acme/observability/ObservabilityTest.java @@ -59,7 +59,8 @@ public class ObservabilityTest { .then() .statusCode(200) .body("status", Matchers.is("UP"), - "checks.name", containsInAnyOrder("camel-readiness-checks", "camel", "Uptime readiness check"), + "checks.name", + containsInAnyOrder("camel-readiness-checks", "camel-context-check", "Uptime readiness check"), "checks.data.custom-readiness-check", containsInAnyOrder(null, "UP")); } } diff --git a/examples/pom.xml b/examples/pom.xml index cacb3e9..1ed0651 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -34,6 +34,7 @@ <modules> <module>observability</module> <module>http-log</module> + <module>health</module> <module>rest-json</module> <module>timer-log</module> <module>timer-log-cdi</module> diff --git a/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/health/MicroProfileHealthTest.java b/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/health/MicroProfileHealthTest.java index bb44949..49e36ba 100644 --- a/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/health/MicroProfileHealthTest.java +++ b/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/health/MicroProfileHealthTest.java @@ -35,7 +35,8 @@ class MicroProfileHealthTest { .header("Content-Type", containsString("charset=UTF-8")) .body("status", is("UP"), "checks.status", containsInAnyOrder("UP", "UP", "UP"), - "checks.name", containsInAnyOrder("camel-readiness-checks", "camel-liveness-checks", "camel"), + "checks.name", + containsInAnyOrder("camel-readiness-checks", "camel-liveness-checks", "camel-context-check"), "checks.data.contextStatus", containsInAnyOrder(null, null, "Started"), "checks.data.'route:healthyRoute'", containsInAnyOrder(null, null, "UP"), "checks.data.name", containsInAnyOrder(null, null, "quarkus-camel-example")); @@ -54,7 +55,7 @@ class MicroProfileHealthTest { .body("status", is("DOWN"), "checks.status", containsInAnyOrder("DOWN", "UP", "DOWN"), "checks.name", - containsInAnyOrder("camel-readiness-checks", "camel", "camel-liveness-checks"), + containsInAnyOrder("camel-readiness-checks", "camel-context-check", "camel-liveness-checks"), "checks.data.contextStatus", containsInAnyOrder(null, null, "Started"), "checks.data.name", containsInAnyOrder(null, null, "quarkus-camel-example")); @@ -107,7 +108,7 @@ class MicroProfileHealthTest { .header("Content-Type", containsString("charset=UTF-8")) .body("status", is("UP"), "checks.status", containsInAnyOrder("UP", "UP"), - "checks.name", containsInAnyOrder("camel-readiness-checks", "camel"), + "checks.name", containsInAnyOrder("camel-readiness-checks", "camel-context-check"), "checks.data.contextStatus", containsInAnyOrder(null, "Started"), "checks.data.name", containsInAnyOrder(null, "quarkus-camel-example"), "checks.data.test-readiness", containsInAnyOrder(null, "UP")); @@ -125,7 +126,7 @@ class MicroProfileHealthTest { .header("Content-Type", containsString("charset=UTF-8")) .body("status", is("DOWN"), "checks.status", containsInAnyOrder("UP", "DOWN"), - "checks.name", containsInAnyOrder("camel-readiness-checks", "camel"), + "checks.name", containsInAnyOrder("camel-readiness-checks", "camel-context-check"), "checks.data.contextStatus", containsInAnyOrder(null, "Started"), "checks.data.name", containsInAnyOrder(null, "quarkus-camel-example"), "checks.data.test-readiness", containsInAnyOrder(null, "UP"));