You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/11/18 09:00:42 UTC

[camel] branch CAMEL-13691 created (now a502504)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git.


      at a502504  CAMEL-13691: camel-resilience4j - WIP

This branch includes the following new commits:

     new bc97403  CAMEL-13691: camel-resilience4j - WIP
     new 3693d53  CAMEL-13691: camel-resilience4j - WIP
     new f42465f  CAMEL-13691: camel-resilience4j - WIP
     new 4bcef58  CAMEL-13691: camel-resilience4j - WIP
     new f3e97b1  CAMEL-13691: camel-resilience4j - WIP
     new d8cec60  CAMEL-13691: camel-resilience4j - WIP
     new da3bf41  CAMEL-13691: camel-resilience4j - WIP
     new 1cd632f  CAMEL-13691: camel-resilience4j - WIP
     new 4e8ea9d  CAMEL-13691: camel-resilience4j - WIP
     new dc6bf8a  CAMEL-13691: camel-resilience4j - WIP
     new db108f8  CAMEL-13691: camel-resilience4j - WIP
     new 2cf5880  CAMEL-13691: camel-resilience4j - WIP
     new bc493f5  CAMEL-13691: camel-resilience4j - WIP
     new 1960eee  CAMEL-13691: camel-resilience4j - WIP
     new 0773537  CAMEL-13691: camel-resilience4j - WIP
     new d59416a  CAMEL-13691: camel-resilience4j - WIP
     new cc808de  CAMEL-13691: camel-resilience4j - WIP
     new 58edbb5  CAMEL-13691: camel-resilience4j - WIP
     new f1bd476  CAMEL-14186: camel-core-starter - Spring Boot auto-configuration is not generated for some models
     new da9c01a  CAMEL-13691: camel-resilience4j - WIP
     new 008e02d  CAMEL-13691: camel-resilience4j - WIP
     new 6258c4f  CAMEL-13691: camel-resilience4j - WIP
     new a502504  CAMEL-13691: camel-resilience4j - WIP

The 23 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[camel] 22/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6258c4fc88957505c4f16a006446d1fedb146ed8
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 09:25:53 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../itest/springboot/CamelResilience4jTest.java    | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/tests/camel-itest-spring-boot/src/test/java/org/apache/camel/itest/springboot/CamelResilience4jTest.java b/tests/camel-itest-spring-boot/src/test/java/org/apache/camel/itest/springboot/CamelResilience4jTest.java
new file mode 100644
index 0000000..458e899
--- /dev/null
+++ b/tests/camel-itest-spring-boot/src/test/java/org/apache/camel/itest/springboot/CamelResilience4jTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.itest.springboot;
+
+import org.apache.camel.itest.springboot.util.ArquillianPackager;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(Arquillian.class)
+public class CamelResilience4jTest extends AbstractSpringBootTestSupport {
+
+    @Deployment
+    public static Archive<?> createSpringBootPackage() throws Exception {
+        return ArquillianPackager.springBootPackage(createTestConfig());
+    }
+
+    public static ITestConfig createTestConfig() {
+        return new ITestConfigBuilder()
+                .module(inferModuleName(CamelResilience4jTest.class))
+                .unitTestExclusionPattern(".*(\\.integration\\..*|IntegrationTest$|BlueprintResilienceRouteOkTest$|BlueprintResilienceRouteFallbackTest$)")
+                .build();
+    }
+
+    @Test
+    public void componentTests() throws Exception {
+        // no component test
+        this.runModuleUnitTestsIfEnabled(config);
+    }
+
+}


[camel] 02/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 3693d53fe526f5bcd194ca528e1000aed6d997ad
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Nov 16 11:18:36 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 apache-camel/pom.xml                               |  10 ++
 apache-camel/src/main/descriptors/common-bin.xml   |   2 +
 components/camel-resilience4j/pom.xml              |  10 ++
 .../src/main/docs/resilience4j.adoc                |  12 +-
 .../resilience4j/ResilienceProcessor.java          | 132 ++++++++++++++-------
 .../component/resilience4j/ResilienceReifier.java  |   4 +
 docs/components/modules/ROOT/nav.adoc              |   1 +
 docs/components/modules/ROOT/pages/index.adoc      |   4 +-
 .../modules/ROOT/pages}/resilience4j.adoc          |  13 +-
 parent/pom.xml                                     |  10 ++
 10 files changed, 140 insertions(+), 58 deletions(-)

diff --git a/apache-camel/pom.xml b/apache-camel/pom.xml
index d691527..cd3c1b0 100644
--- a/apache-camel/pom.xml
+++ b/apache-camel/pom.xml
@@ -1228,6 +1228,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-resilience4j</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-rest</artifactId>
       <version>${project.version}</version>
     </dependency>
@@ -2782,6 +2787,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-resilience4j-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-rest-starter</artifactId>
       <version>${project.version}</version>
     </dependency>
diff --git a/apache-camel/src/main/descriptors/common-bin.xml b/apache-camel/src/main/descriptors/common-bin.xml
index fe4a531..213ce4f 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -266,6 +266,7 @@
         <include>org.apache.camel:camel-reactive-streams</include>
         <include>org.apache.camel:camel-reactor</include>
         <include>org.apache.camel:camel-ref</include>
+        <include>org.apache.camel:camel-resilience4j</include>
         <include>org.apache.camel:camel-rest</include>
         <include>org.apache.camel:camel-rest-swagger</include>
         <include>org.apache.camel:camel-ribbon</include>
@@ -616,6 +617,7 @@
         <include>org.apache.camel:camel-reactive-streams-starter</include>
         <include>org.apache.camel:camel-reactor-starter</include>
         <include>org.apache.camel:camel-ref-starter</include>
+        <include>org.apache.camel:camel-resilience4j-starter</include>
         <include>org.apache.camel:camel-rest-starter</include>
         <include>org.apache.camel:camel-rest-swagger-starter</include>
         <include>org.apache.camel:camel-ribbon-starter</include>
diff --git a/components/camel-resilience4j/pom.xml b/components/camel-resilience4j/pom.xml
index fa396b4..71f185f 100644
--- a/components/camel-resilience4j/pom.xml
+++ b/components/camel-resilience4j/pom.xml
@@ -50,6 +50,16 @@
             <artifactId>resilience4j-circuitbreaker</artifactId>
             <version>1.1.0</version>
         </dependency>
+        <dependency>
+            <groupId>io.github.resilience4j</groupId>
+            <artifactId>resilience4j-bulkhead</artifactId>
+            <version>1.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.github.resilience4j</groupId>
+            <artifactId>resilience4j-timelimiter</artifactId>
+            <version>1.1.0</version>
+        </dependency>
 
         <!-- for testing -->
         <dependency>
diff --git a/components/camel-resilience4j/src/main/docs/resilience4j.adoc b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
index 9afc96e..0bf1b56 100644
--- a/components/camel-resilience4j/src/main/docs/resilience4j.adoc
+++ b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
@@ -1,10 +1,10 @@
-= Hystrix Component
+= Resilience4j Component
 
-*Since Camel 2.18*
+*Since Camel 3.0*
 
-The Hystrix component integrates Netflix Hystrix circuit breaker in Camel routes.
+This component supports the Circuit Breaker EIP with the Resilience4j library.
 
-For more details see the Hystrix EIP documentation.
+For more details see the Circuit Breaker EIP documentation.
 
 Maven users will need to add the following dependency to their `pom.xml`
 for this component:
@@ -13,7 +13,7 @@ for this component:
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
-    <artifactId>camel-hystrix</artifactId>
+    <artifactId>camel-resilience4j</artifactId>
     <version>x.x.x</version>
     <!-- use the same version as your Camel core version -->
 </dependency>
@@ -28,7 +28,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 <dependency>
   <groupId>org.apache.camel</groupId>
-  <artifactId>camel-hystrix-starter</artifactId>
+  <artifactId>camel-resilience4j-starter</artifactId>
   <version>x.x.x</version>
   <!-- use the same version as your Camel core version -->
 </dependency>
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index a9bd0e7..17be13f 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -18,7 +18,8 @@ package org.apache.camel.component.resilience4j;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
+import java.util.function.Function;
+import java.util.function.Supplier;
 
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.vavr.control.Try;
@@ -26,6 +27,7 @@ import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
+import org.apache.camel.RuntimeExchangeException;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
@@ -90,9 +92,50 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         // run this as if we run inside try .. catch so there is no regular Camel error handler
         exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true);
 
+//        Supplier<CompletableFuture<String>> futureSupplier = () -> CompletableFuture.supplyAsync(() -> "Hello");
+//        Callable<String> callable = TimeLimiter.decorateFutureSupplier(TimeLimiter.of(Duration.ofMillis(500)), futureSupplier);
+//        String result = CircuitBreaker.decorateCheckedSupplier(cb, callable::call).apply();
+
+//        Bulkhead bh = Bulkhead.ofDefaults("ddd");
+//        BulkheadConfig.
+
+//                TimeLimiter time = TimeLimiter.of(Duration.ofSeconds(1));
+//        Supplier<Future<Exchange>> task2 = time.decorateFutureSupplier(() -> {
+//            task.get();
+//            Future
+//        });
+
         CircuitBreaker cb = CircuitBreaker.ofDefaults(id);
+        Supplier<Exchange> task = CircuitBreaker.decorateSupplier(cb, new CircuitBreakerTask(processor, exchange));
+        Try.ofSupplier(task)
+                .recover(new CircuitBreakerFallbackTask(fallback, exchange))
+                .andFinally(() -> callback.done(false)).get();
+
+        return false;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        // noop
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // noop
+    }
+
+    private static class CircuitBreakerTask implements Supplier<Exchange> {
+
+        private final Processor processor;
+        private final Exchange exchange;
+
+        private CircuitBreakerTask(Processor processor, Exchange exchange) {
+            this.processor = processor;
+            this.exchange = exchange;
+        }
 
-        Callable task = CircuitBreaker.decorateCallable(cb, () -> {
+        @Override
+        public Exchange get() {
             try {
                 LOG.debug("Running processor: {} with exchange: {}", processor, exchange);
                 // prepare a copy of exchange so downstream processors don't cause side-effects if they mutate the exchange
@@ -113,53 +156,52 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
             }
             if (exchange.getException() != null) {
                 // throw exception so resilient4j know it was a failure
-                throw exchange.getException();
+                throw RuntimeExchangeException.wrapRuntimeException(exchange.getException());
             }
-            return null;
-        });
-
-        Try.ofCallable(task)
-                .recover(f -> {
-                    if (fallback != null) {
-                        // store the last to endpoint as the failure endpoint
-                        if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
-                            exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
-                        }
-                        // give the rest of the pipeline another chance
-                        exchange.setProperty(Exchange.EXCEPTION_HANDLED, true);
-                        exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException());
-                        exchange.removeProperty(Exchange.ROUTE_STOP);
-                        exchange.setException(null);
-                        // and we should not be regarded as exhausted as we are in a try .. catch block
-                        exchange.removeProperty(Exchange.REDELIVERY_EXHAUSTED);
-                        // run the fallback processor
-                        try {
-                            LOG.debug("Running fallback: {} with exchange: {}", fallback, exchange);
-                            // process the fallback until its fully done
-                            fallback.process(exchange);
-                            LOG.debug("Running fallback: {} with exchange: {} done", fallback, exchange);
-                        } catch (Exception e) {
-                            exchange.setException(e);
-                        }
-
-                        exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
-                        exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
-                    }
-                    return null;
-                })
-                .andFinally(() -> callback.done(false)).get();
-
-        return false;
+            return exchange;
+        }
     }
 
-    @Override
-    protected void doStart() throws Exception {
-        // noop
-    }
+    private static class CircuitBreakerFallbackTask implements Function<Throwable, Exchange> {
 
-    @Override
-    protected void doStop() throws Exception {
-        // noop
+        private final Processor processor;
+        private final Exchange exchange;
+
+        private CircuitBreakerFallbackTask(Processor processor, Exchange exchange) {
+            this.processor = processor;
+            this.exchange = exchange;
+        }
+
+        @Override
+        public Exchange apply(Throwable throwable) {
+            if (processor != null) {
+                // store the last to endpoint as the failure endpoint
+                if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
+                    exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
+                }
+                // give the rest of the pipeline another chance
+                exchange.setProperty(Exchange.EXCEPTION_HANDLED, true);
+                exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException());
+                exchange.removeProperty(Exchange.ROUTE_STOP);
+                exchange.setException(null);
+                // and we should not be regarded as exhausted as we are in a try .. catch block
+                exchange.removeProperty(Exchange.REDELIVERY_EXHAUSTED);
+                // run the fallback processor
+                try {
+                    LOG.debug("Running fallback: {} with exchange: {}", processor, exchange);
+                    // process the fallback until its fully done
+                    processor.process(exchange);
+                    LOG.debug("Running fallback: {} with exchange: {} done", processor, exchange);
+                } catch (Exception e) {
+                    exchange.setException(e);
+                }
+
+                exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+                exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+            }
+
+            return exchange;
+        }
     }
 
 }
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 1a07f57..4bd1278 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -23,6 +23,10 @@ import org.apache.camel.spi.RouteContext;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
+    // TODO: Resilience configuration in camel-core / model
+    // TODO: Timeout
+    // TODO: Bulkhead for viaNetwork
+
     public ResilienceReifier(CircuitBreakerDefinition definition) {
         super(definition);
     }
diff --git a/docs/components/modules/ROOT/nav.adoc b/docs/components/modules/ROOT/nav.adoc
index 4473bc1..d53b85c 100644
--- a/docs/components/modules/ROOT/nav.adoc
+++ b/docs/components/modules/ROOT/nav.adoc
@@ -288,6 +288,7 @@
 * xref:reactive-streams-component.adoc[Reactive Streams Component]
 * xref:reactor.adoc[Reactor Component]
 * xref:ref-component.adoc[Ref Component]
+* xref:resilience4j.adoc[Resilience4j Component]
 * xref:rest-swagger-component.adoc[REST Swagger Component]
 * xref:rest-api-component.adoc[REST API Component]
 * xref:rest-component.adoc[REST Component]
diff --git a/docs/components/modules/ROOT/pages/index.adoc b/docs/components/modules/ROOT/pages/index.adoc
index e80b4f3..0c7a425 100644
--- a/docs/components/modules/ROOT/pages/index.adoc
+++ b/docs/components/modules/ROOT/pages/index.adoc
@@ -772,7 +772,7 @@ Number of Languages: 17 in 11 JAR artifacts (0 deprecated)
 == Miscellaneous Components
 
 // others: START
-Number of Miscellaneous Components: 38 in 38 JAR artifacts (0 deprecated)
+Number of Miscellaneous Components: 39 in 39 JAR artifacts (0 deprecated)
 
 [width="100%",cols="4,1,5",options="header"]
 |===
@@ -808,6 +808,8 @@ Number of Miscellaneous Components: 38 in 38 JAR artifacts (0 deprecated)
 
 | xref:reactor.adoc[Reactor] (camel-reactor) | 2.20 | Reactor based back-end for Camel's reactive streams component
 
+| xref:resilience4j.adoc[Resilience4j] (camel-resilience4j) | 3.0 | Circuit Breaker EIP using Resilience4j
+
 | xref:ribbon.adoc[Ribbon] (camel-ribbon) | 2.18 | Using Netflix Ribbon for client side load balancing
 
 | xref:rxjava.adoc[RxJava] (camel-rxjava) | 2.22 | RxJava based back-end for Camel's reactive streams component
diff --git a/components/camel-resilience4j/src/main/docs/resilience4j.adoc b/docs/components/modules/ROOT/pages/resilience4j.adoc
similarity index 77%
copy from components/camel-resilience4j/src/main/docs/resilience4j.adoc
copy to docs/components/modules/ROOT/pages/resilience4j.adoc
index 9afc96e..6801015 100644
--- a/components/camel-resilience4j/src/main/docs/resilience4j.adoc
+++ b/docs/components/modules/ROOT/pages/resilience4j.adoc
@@ -1,10 +1,11 @@
-= Hystrix Component
+= Resilience4j Component
+:page-source: components/camel-resilience4j/src/main/docs/resilience4j.adoc
 
-*Since Camel 2.18*
+*Since Camel 3.0*
 
-The Hystrix component integrates Netflix Hystrix circuit breaker in Camel routes.
+This component supports the Circuit Breaker EIP with the Resilience4j library.
 
-For more details see the Hystrix EIP documentation.
+For more details see the Circuit Breaker EIP documentation.
 
 Maven users will need to add the following dependency to their `pom.xml`
 for this component:
@@ -13,7 +14,7 @@ for this component:
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
-    <artifactId>camel-hystrix</artifactId>
+    <artifactId>camel-resilience4j</artifactId>
     <version>x.x.x</version>
     <!-- use the same version as your Camel core version -->
 </dependency>
@@ -28,7 +29,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 <dependency>
   <groupId>org.apache.camel</groupId>
-  <artifactId>camel-hystrix-starter</artifactId>
+  <artifactId>camel-resilience4j-starter</artifactId>
   <version>x.x.x</version>
   <!-- use the same version as your Camel core version -->
 </dependency>
diff --git a/parent/pom.xml b/parent/pom.xml
index 6bbc2a4..4c02d65 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1963,6 +1963,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-rest</artifactId>
         <version>${project.version}</version>
       </dependency>
@@ -3537,6 +3542,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-rest-starter</artifactId>
         <version>${project.version}</version>
       </dependency>


[camel] 09/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 4e8ea9dc666fa3019ecc1192add4aa4281bf9e18
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 09:16:33 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../java/org/apache/camel/maven/PrepareCamelMainMojo.java   | 13 ++++++++++---
 .../maven/packaging/SpringBootAutoConfigurationMojo.java    | 13 +++++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java b/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
index 00809b5..cd35afc 100644
--- a/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
+++ b/tooling/maven/camel-main-package-maven-plugin/src/main/java/org/apache/camel/maven/PrepareCamelMainMojo.java
@@ -74,6 +74,8 @@ public class PrepareCamelMainMojo extends AbstractMojo {
                 String prefix;
                 if (file.getName().contains("Hystrix")) {
                     prefix = "camel.hystrix.";
+                } else if (file.getName().contains("Resilience")) {
+                    prefix = "camel.resilience4j.";
                 } else if (file.getName().contains("Rest")) {
                     prefix = "camel.rest.";
                 } else {
@@ -143,12 +145,17 @@ public class PrepareCamelMainMojo extends AbstractMojo {
             group2.put("description", "camel-hystrix configurations.");
             group2.put("sourceType", "org.apache.camel.main.HystrixConfigurationProperties");
             Map group3 = new LinkedHashMap();
-            group3.put("name", "camel.rest");
-            group3.put("description", "camel-rest configurations.");
-            group3.put("sourceType", "org.apache.camel.spi.RestConfiguration");
+            group3.put("name", "camel.resilience4j");
+            group3.put("description", "camel-resilience4j configurations.");
+            group3.put("sourceType", "org.apache.camel.main.Resilience4jConfigurationProperties");
+            Map group4 = new LinkedHashMap();
+            group4.put("name", "camel.rest");
+            group4.put("description", "camel-rest configurations.");
+            group4.put("sourceType", "org.apache.camel.spi.RestConfiguration");
             groups.add(group1);
             groups.add(group2);
             groups.add(group3);
+            groups.add(group4);
 
             Map map = new LinkedHashMap();
             map.put("groups", groups);
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
index 0b022bc..32d6dce 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
@@ -255,6 +255,19 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             createOtherModelConfigurationSource(pkg, model, "camel.hystrix", true);
         }
 
+        // Resilience4j
+        json = loadModelJson(files, "resilience4jConfiguration");
+        if (json != null) {
+            OtherModel model = generateOtherModel(json);
+
+            int pos = model.getJavaType().lastIndexOf(".");
+            String pkg = model.getJavaType().substring(0, pos) + ".springboot";
+
+            // Generate properties, auto-configuration happens in
+            // camel-resilience4j-starter
+            createOtherModelConfigurationSource(pkg, model, "camel.resilience4j", true);
+        }
+
         // Consul
         json = loadModelJson(files, "consulServiceDiscovery");
         if (json != null) {


[camel] 18/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 58edbb57b3887bb252493620d9e5b66883c60260
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 06:36:50 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../component/resilience4j/ResilienceReifier.java  |   1 -
 examples/camel-example-resilience4j/README.adoc    |  72 ++++++++
 examples/camel-example-resilience4j/client/pom.xml |  93 ++++++++++
 .../main/java/sample/camel/ClientApplication.java  |  35 ++++
 .../src/main/java/sample/camel/ClientRoute.java    |  44 +++++
 .../src/main/java/sample/camel/CounterBean.java    |  30 +++
 .../client/src/main/resources/META-INF/LICENSE.txt | 203 +++++++++++++++++++++
 .../client/src/main/resources/META-INF/NOTICE.txt  |  11 ++
 .../client/src/main/resources/META-INF/beans.xml   |  20 ++
 .../src/main/resources/application.properties      |  30 +++
 .../client/src/main/resources/log4j2.properties    |  25 +++
 examples/camel-example-resilience4j/pom.xml        |  46 +++++
 .../camel-example-resilience4j/service1/pom.xml    |  97 ++++++++++
 .../java/sample/camel/Service1Application.java     |  37 ++++
 .../src/main/java/sample/camel/Service1Route.java  |  33 ++++
 .../src/main/resources/META-INF/LICENSE.txt        | 203 +++++++++++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt         |  11 ++
 .../src/main/resources/application.properties      |  25 +++
 .../camel-example-resilience4j/service2/pom.xml    | 109 +++++++++++
 .../java/sample/camel/Service2Application.java     |  34 ++++
 .../src/main/java/sample/camel/Service2Route.java  |  31 ++++
 .../src/main/resources/META-INF/LICENSE.txt        | 203 +++++++++++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt         |  11 ++
 .../service2/src/main/resources/log4j2.properties  |  25 +++
 examples/pom.xml                                   |   1 +
 25 files changed, 1429 insertions(+), 1 deletion(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 0e89786..c7d31d8 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -48,7 +48,6 @@ import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
     // TODO: spring-boot allow to configure via resilience4j-spring-boot
-    // TODO: example
     // TODO: camel-main - configure hystrix/resilience/rest via java code fluent builder (does it work)
 
     public ResilienceReifier(CircuitBreakerDefinition definition) {
diff --git a/examples/camel-example-resilience4j/README.adoc b/examples/camel-example-resilience4j/README.adoc
new file mode 100644
index 0000000..6330443
--- /dev/null
+++ b/examples/camel-example-resilience4j/README.adoc
@@ -0,0 +1,72 @@
+== Resilience4j Example
+
+=== Introduction
+
+This example shows how to use Camel with Resilience4j EIP as circuit breaker
+in Camel routes
+
+The example includes three sub maven modules that implement
+
+* client
+* service1
+* service2
+
+Where client -> service1 client -> service2 (fallback)
+
+=== Configuration
+
+Service1 is configured in the
+`+src/main/java/sample/camel/Service1Application.java+` source code.
+Service2 is configured in the
+`+src/main/resources/application.properties+` properties file.
+
+=== Build
+
+You will need to compile this example first:
+
+[source,sh]
+----
+$ mvn compile
+----
+
+=== Run the example
+
+Then using three different shells and run service1 and service2 before
+the client.
+
+[source,sh]
+----
+$ cd service1
+$ mvn compile spring-boot:run
+----
+
+When service1 is ready then start service2
+
+[source,sh]
+----
+$ cd service2
+$ mvn compile camel:run
+----
+
+And then start the client that calls service1 every second.
+
+[source,sh]
+----
+$ cd client
+$ mvn compile spring-boot:run
+----
+
+You can then stop service1 and see that the client should fallback to
+call service2 in the Resilience EIP circuit breaker. And then start service
+1 again and see the Resilience EIP go back to normal.
+
+
+=== 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/camel-example-resilience4j/client/pom.xml b/examples/camel-example-resilience4j/client/pom.xml
new file mode 100644
index 0000000..d29fede
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/pom.xml
@@ -0,0 +1,93 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.example</groupId>
+        <artifactId>camel-example-resilience4j</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-resilience4j-client</artifactId>
+    <name>Camel :: Example :: Resilience4j :: Client</name>
+    <description>An example showing how to use Resilience4j EIP as circuit breaker in Camel routes</description>
+
+    <properties>
+        <spring.boot-version>${spring-boot-version}</spring.boot-version>
+    </properties>
+
+    <!-- import Spring-Boot and Camel BOM -->
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring.boot-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-spring-boot-dependencies</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- spring-boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- camel -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-http-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-resilience4j-starter</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot-version}</version>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientApplication.java b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientApplication.java
new file mode 100644
index 0000000..bda2eab
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientApplication.java
@@ -0,0 +1,35 @@
+/*
+ * 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 sample.camel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * A Spring Boot application that runs the Camel Resilience client application that calls service 1 and service 2 (as fallback)
+ */
+@SpringBootApplication
+public class ClientApplication {
+
+    /**
+     * A main method to start this application.
+     */
+    public static void main(String[] args) {
+        SpringApplication.run(ClientApplication.class, args);
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientRoute.java b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientRoute.java
new file mode 100644
index 0000000..1edd6f6
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/ClientRoute.java
@@ -0,0 +1,44 @@
+/*
+ * 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 sample.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ClientRoute extends RouteBuilder {
+
+    @Override
+    public void configure() {
+        // you can configure the route rule with Java DSL here
+        from("timer:trigger?period=500").streamCaching()
+            .bean("counterBean")
+            .log(" Client request: ${body}")
+            .circuitBreaker()
+                // see application.properties how resilience is configured
+                .to("http://localhost:9090/service1")
+            //.onFallback()
+            // we use a fallback without network that provides a response message immediately
+            //    .transform().simple("Fallback ${body}")
+            .onFallback()
+                // we use fallback via network where we call a 2nd service
+                .to("http://localhost:7070/service2")
+            .end()
+            .log("Client response: ${body}");
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/client/src/main/java/sample/camel/CounterBean.java b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/CounterBean.java
new file mode 100644
index 0000000..e5dc4cd
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/java/sample/camel/CounterBean.java
@@ -0,0 +1,30 @@
+/*
+ * 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 sample.camel;
+
+import org.springframework.stereotype.Component;
+
+@Component("counterBean")
+public class CounterBean {
+
+    private int counter;
+
+    public String someMethod(String body) {
+        return "" + ++counter;
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/META-INF/beans.xml b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..4d1f3eb
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,20 @@
+<?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.
+
+-->
+<beans/>
\ No newline at end of file
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/application.properties b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
new file mode 100644
index 0000000..c3a7ed9
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
@@ -0,0 +1,30 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+server.port=8080
+
+# configure resilience4j
+# when we have more than 5 requests per 10 seconds that 50%+ fails
+# then open circuit and call fallback immediately
+// TODO: configure these
+camel.resilience.sliding-window-type=
+camel.hystrix.circuit-breaker-request-volume-threshold=5
+camel.hystrix.circuit-breaker-error-threshold-percentage=50
+camel.hystrix.metrics-rolling-percentile-window-in-milliseconds=10000
+
+# resilience4j logging
+#logging.level.org.apache.camel.component.resilience=DEBUG
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties b/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..6f76518
--- /dev/null
+++ b/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
@@ -0,0 +1,25 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.stdout.type = Console
+appender.stdout.name = stdout
+appender.stdout.layout.type = PatternLayout
+appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+logger.zipkin.name = org.apache.camel.zipkin
+logger.zipkin.level = DEBUG
+rootLogger.level = INFO
+rootLogger.appenderRef.stdout.ref = stdout
diff --git a/examples/camel-example-resilience4j/pom.xml b/examples/camel-example-resilience4j/pom.xml
new file mode 100644
index 0000000..4473c22
--- /dev/null
+++ b/examples/camel-example-resilience4j/pom.xml
@@ -0,0 +1,46 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.example</groupId>
+        <artifactId>examples</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-resilience4j</artifactId>
+    <packaging>pom</packaging>
+    <name>Camel :: Example :: Resilience4j</name>
+    <description>An example showing how to use Resilience4j EIP as circuit breaker in Camel routes</description>
+
+    <properties>
+        <category>EIP</category>
+    </properties>
+
+    <modules>
+        <module>client</module>
+        <module>service1</module>
+        <module>service2</module>
+    </modules>
+
+</project>
diff --git a/examples/camel-example-resilience4j/service1/pom.xml b/examples/camel-example-resilience4j/service1/pom.xml
new file mode 100644
index 0000000..2875894
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/pom.xml
@@ -0,0 +1,97 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.example</groupId>
+        <artifactId>camel-example-resilience4j</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-resilience4j-service1</artifactId>
+    <name>Camel :: Example :: Resilience4j :: Service 1</name>
+    <description>An example showing how to use Resilience4j EIP as circuit breaker in Camel routes</description>
+
+    <properties>
+        <spring.boot-version>${spring-boot-version}</spring.boot-version>
+    </properties>
+
+    <!-- import Spring-Boot and Camel BOM -->
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring.boot-version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-spring-boot-dependencies</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- spring-boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- camel -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-resilience4j-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-jetty-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-http-starter</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot-version}</version>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Application.java b/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Application.java
new file mode 100644
index 0000000..0fd7a26
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Application.java
@@ -0,0 +1,37 @@
+/*
+ * 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 sample.camel;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+//CHECKSTYLE:OFF
+/**
+ * A Spring Boot application that runs Camel service 1
+ */
+@SpringBootApplication
+public class Service1Application {
+
+    /**
+     * A main method to start this application.
+     */
+    public static void main(String[] args) {
+        SpringApplication.run(Service1Application.class, args);
+    }
+
+}
+//CHECKSTYLE:ON
diff --git a/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Route.java b/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Route.java
new file mode 100644
index 0000000..4d82ea0
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/src/main/java/sample/camel/Service1Route.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 sample.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Service1Route extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("jetty:http://0.0.0.0:{{service1.port}}/service1").routeId("service1").streamCaching()
+            .log("Service1 request: ${body}")
+            .transform(simple("Service1-${body}"))
+            .log("Service1 response: ${body}");
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/examples/camel-example-resilience4j/service1/src/main/resources/application.properties b/examples/camel-example-resilience4j/service1/src/main/resources/application.properties
new file mode 100644
index 0000000..94a862b
--- /dev/null
+++ b/examples/camel-example-resilience4j/service1/src/main/resources/application.properties
@@ -0,0 +1,25 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+# the name of Camel
+camel.springboot.name=Service1
+camel.springboot.main-run-controller=true
+
+# the port number the service will use for accepting incoming HTTP requests
+service1.port=9090
+service2.port=7070
+
diff --git a/examples/camel-example-resilience4j/service2/pom.xml b/examples/camel-example-resilience4j/service2/pom.xml
new file mode 100644
index 0000000..82a5023
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/pom.xml
@@ -0,0 +1,109 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.example</groupId>
+        <artifactId>camel-example-resilience4j</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-resilience4j-service2</artifactId>
+    <name>Camel :: Example :: Resilience4j :: Service 2</name>
+    <description>An example showing how to use Resilience4j EIP as circuit breaker in Camel routes</description>
+
+    <!-- import Camel BOM -->
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-bom</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- camel-core -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-resilience4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-undertow</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+
+        <plugins>
+            <!-- allows the routes to be run via 'mvn camel:run' -->
+            <plugin>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-maven-plugin</artifactId>
+                <version>${project.version}</version>
+                <configuration>
+                    <mainClass>sample.camel.Service2Application</mainClass>
+                </configuration>
+                <dependencies>
+                    <!-- logging -->
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-api</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-core</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-slf4j-impl</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-1.2-api</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+
+    </build>
+
+</project>
diff --git a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
new file mode 100644
index 0000000..2fee2d9
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
@@ -0,0 +1,34 @@
+/*
+ * 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 sample.camel;
+
+import org.apache.camel.main.Main;
+
+//CHECKSTYLE:OFF
+/**
+ * A Java main that runs Camel service 2
+ */
+public class Service2Application {
+
+    public static void main(String[] args) throws Exception {
+        Main main = new Main();
+        main.addRoutesBuilder(new Service2Route());
+        main.run();
+    }
+
+}
+//CHECKSTYLE:ON
\ No newline at end of file
diff --git a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Route.java b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Route.java
new file mode 100644
index 0000000..8e3ff80
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Route.java
@@ -0,0 +1,31 @@
+/*
+ * 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 sample.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class Service2Route extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("undertow:http://0.0.0.0:7070/service2").routeId("service2").streamCaching()
+                .log(" Service2 request: ${body}")
+                .transform(simple("Service2-${body}"))
+                .log("Service2 response: ${body}");
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/examples/camel-example-resilience4j/service2/src/main/resources/log4j2.properties b/examples/camel-example-resilience4j/service2/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..6f76518
--- /dev/null
+++ b/examples/camel-example-resilience4j/service2/src/main/resources/log4j2.properties
@@ -0,0 +1,25 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.stdout.type = Console
+appender.stdout.name = stdout
+appender.stdout.layout.type = PatternLayout
+appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+logger.zipkin.name = org.apache.camel.zipkin
+logger.zipkin.level = DEBUG
+rootLogger.level = INFO
+rootLogger.appenderRef.stdout.ref = stdout
diff --git a/examples/pom.xml b/examples/pom.xml
index 8a084ce..315e3bf 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -102,6 +102,7 @@
         <module>camel-example-rabbitmq</module>
         <module>camel-example-reactive-executor-vertx</module>
         <module>camel-example-reactive-streams</module>
+        <module>camel-example-resilience4j</module>
         <module>camel-example-rest-producer</module>
         <module>camel-example-rest-swagger</module>
         <module>camel-example-route-throttling</module>


[camel] 15/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 07735378728cd7ef6a3c3b79a00442d90f22d035
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 05:42:41 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          | 12 +++-
 .../component/resilience4j/ResilienceReifier.java  |  7 +++
 .../ResilienceExistingCircuitBreakerTest.java      | 68 ++++++++++++++++++++++
 .../model/Resilience4jConfigurationCommon.java     | 16 +++++
 .../model/Resilience4jConfigurationDefinition.java | 11 ++++
 .../main/Resilience4jConfigurationProperties.java  | 24 ++++++++
 .../camel-main-configuration-metadata.json         |  6 ++
 .../modules/ROOT/pages/resilience4j.adoc           | 12 ----
 8 files changed, 143 insertions(+), 13 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index c936a9e..93eea8e 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -99,6 +99,14 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements CamelC
         this.id = id;
     }
 
+    public CircuitBreaker getCircuitBreaker() {
+        return circuitBreaker;
+    }
+
+    public void setCircuitBreaker(CircuitBreaker circuitBreaker) {
+        this.circuitBreaker = circuitBreaker;
+    }
+
     public boolean isShutdownExecutorService() {
         return shutdownExecutorService;
     }
@@ -374,7 +382,9 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements CamelC
     @Override
     protected void doStart() throws Exception {
         ObjectHelper.notNull(camelContext, "CamelContext", this);
-        circuitBreaker = CircuitBreaker.of(id, circuitBreakerConfig);
+        if (circuitBreaker == null) {
+            circuitBreaker = CircuitBreaker.of(id, circuitBreakerConfig);
+        }
     }
 
     @Override
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index e9aa90c..0e89786 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -23,6 +23,7 @@ import java.util.Optional;
 import java.util.concurrent.ExecutorService;
 
 import io.github.resilience4j.bulkhead.BulkheadConfig;
+import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 
 import io.github.resilience4j.timelimiter.TimeLimiterConfig;
@@ -37,6 +38,7 @@ import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.reifier.ProcessorReifier;
 import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.RouteContext;
+import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.util.function.Suppliers;
 
@@ -72,6 +74,11 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
 
         ResilienceProcessor answer = new ResilienceProcessor(cbConfig, bhConfig, tlConfig, processor, fallback);
         configureTimeoutExecutorService(answer, routeContext, config);
+        // using any existing circuit breakers?
+        if (config.getCircuitBreakerRef() != null) {
+            CircuitBreaker cb = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), config.getCircuitBreakerRef(), CircuitBreaker.class);
+            answer.setCircuitBreaker(cb);
+        }
         return answer;
     }
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceExistingCircuitBreakerTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceExistingCircuitBreakerTest.java
new file mode 100644
index 0000000..8892659
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceExistingCircuitBreakerTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.component.resilience4j;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreaker;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ResilienceExistingCircuitBreakerTest extends CamelTestSupport {
+
+    @BindToRegistry
+    public CircuitBreaker myCircuitBreaker() {
+        return CircuitBreaker.ofDefaults("myCircuitBreaker");
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        CircuitBreaker cb = context().getRegistry().lookupByNameAndType("myCircuitBreaker", CircuitBreaker.class);
+        assertNotNull(cb);
+        assertEquals("myCircuitBreaker", cb.getName());
+        assertEquals(0, cb.getMetrics().getNumberOfSuccessfulCalls());
+        assertEquals(1, cb.getMetrics().getNumberOfFailedCalls());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to("log:start")
+                    .circuitBreaker().resilience4jConfiguration().circuitBreakerRef("myCircuitBreaker").end()
+                        .throwException(new IllegalArgumentException("Forced"))
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
index decdd34..15eed28 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -28,6 +28,9 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
 
     @XmlAttribute
     @Metadata(label = "circuitbreaker")
+    private String circuitBreakerRef;
+    @XmlAttribute
+    @Metadata(label = "circuitbreaker")
     private String configRef;
     @XmlAttribute
     @Metadata(label = "circuitbreaker", defaultValue = "50")
@@ -77,6 +80,19 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
     // Getter/Setter
     // -------------------------------------------------------------------------
 
+    public String getCircuitBreakerRef() {
+        return circuitBreakerRef;
+    }
+
+    /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance
+     * to lookup and use from the registry. When using this, then any other circuit breaker options
+     * are not in use.
+     */
+    public void setCircuitBreakerRef(String circuitBreakerRef) {
+        this.circuitBreakerRef = circuitBreakerRef;
+    }
+
     public String getConfigRef() {
         return configRef;
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
index 54d4f0d..f9b100c 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -46,6 +46,17 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
     // -------------------------------------------------------------------------
 
     /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance
+     * to lookup and use from the registry. When using this, then any other circuit breaker options
+     * are not in use.
+     */
+    public Resilience4jConfigurationDefinition circuitBreakerRef(String circuitBreakerRef) {
+        setCircuitBreakerRef(circuitBreakerRef);
+        return this;
+    }
+
+
+    /**
      * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
      * to lookup and use from the registry.
      */
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
index 9292287..35d5c95 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
@@ -25,6 +25,7 @@ public class Resilience4jConfigurationProperties {
 
     private final MainConfigurationProperties parent;
 
+    private String circuitBreakerRef;
     private String configRef;
     private Float failureRateThreshold;
     private Integer permittedNumberOfCallsInHalfOpenState;
@@ -55,6 +56,19 @@ public class Resilience4jConfigurationProperties {
     // getter and setters
     // --------------------------------------------------------------
 
+    public String getCircuitBreakerRef() {
+        return circuitBreakerRef;
+    }
+
+    /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance
+     * to lookup and use from the registry. When using this, then any other circuit breaker options
+     * are not in use.
+     */
+    public void setCircuitBreakerRef(String circuitBreakerRef) {
+        this.circuitBreakerRef = circuitBreakerRef;
+    }
+
     public String getConfigRef() {
         return configRef;
     }
@@ -295,6 +309,16 @@ public class Resilience4jConfigurationProperties {
     }
 
     /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance
+     * to lookup and use from the registry. When using this, then any other circuit breaker options
+     * are not in use.
+     */
+    public Resilience4jConfigurationProperties withCircuitBreakerRef(String circuitBreakerRef) {
+        this.circuitBreakerRef = circuitBreakerRef;
+        return this;
+    }
+
+    /**
      * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
      * to lookup and use from the registry.
      */
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 983efdb..3a6ba44 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -646,6 +646,12 @@
 			"description":"Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a ne [...]
 		},
 		{
+			"name":"camel.resilience4j.circuit-breaker-ref",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup and use from the registry. When using this, then any other circuit breaker options are not in use."
+		},
+		{
 			"name":"camel.resilience4j.config-ref",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
diff --git a/docs/components/modules/ROOT/pages/resilience4j.adoc b/docs/components/modules/ROOT/pages/resilience4j.adoc
index 6801015..396a526 100644
--- a/docs/components/modules/ROOT/pages/resilience4j.adoc
+++ b/docs/components/modules/ROOT/pages/resilience4j.adoc
@@ -35,16 +35,4 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 </dependency>
 ----
 
-
-The component supports 3 options, which are listed below.
-
-
-
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *camel.component.hystrix.mapping.enabled* | Enables the automatic mapping of the hystrics metric servlet into the Spring web context. | true | Boolean
-| *camel.component.hystrix.mapping.path* | Endpoint for hystrix metrics servlet. | /hystrix.stream | String
-| *camel.component.hystrix.mapping.servlet-name* | Name of the Hystrix metrics servlet. | HystrixEventStreamServlet | String
-|===
 // spring-boot-auto-configure options: END


[camel] 01/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit bc9740347c4207110c0ce5582dbd64e695b9074e
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Nov 15 13:26:55 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 components/camel-resilience4j/pom.xml              |  81 ++++++++
 .../src/main/docs/resilience4j.adoc                |  49 +++++
 .../resilience4j/CircuitBreakerConstants.java      |  29 +++
 .../resilience4j/ResilienceProcessor.java          | 165 +++++++++++++++++
 .../resilience4j/ResilienceProcessorFactory.java   |  38 ++++
 .../component/resilience4j/ResilienceReifier.java  |  44 +++++
 .../apache/camel/model/CircuitBreakerDefinition    |  18 ++
 .../BlueprintResilienceRouteFallbackTest.java      |  40 ++++
 .../BlueprintResilienceRouteOkTest.java            |  40 ++++
 .../resilience4j/HystrixCircuitOpenTest.java       | 130 +++++++++++++
 .../HystrixInheritErrorHandlerTest.java            |  58 ++++++
 .../HystrixRouteConfigMaximumSizeTest.java         |  86 +++++++++
 .../resilience4j/HystrixRouteConfigTest.java       |  85 +++++++++
 .../HystrixRouteFallbackViaNetworkTest.java        |  56 ++++++
 .../component/resilience4j/HystrixTimeoutTest.java |  99 ++++++++++
 .../HystrixTimeoutWithFallbackTest.java            |  85 +++++++++
 .../resilience4j/ResilienceRouteFallbackTest.java  |  54 ++++++
 .../resilience4j/ResilienceRouteOkTest.java        |  57 ++++++
 .../SpringHystrixRouteConfigMaximumSizeTest.java   |  44 +++++
 .../SpringHystrixRouteConfigRefTest.java           |  44 +++++
 .../resilience4j/SpringHystrixRouteConfigTest.java |  44 +++++
 .../SpringResilienceRouteFallbackTest.java         |  44 +++++
 .../resilience4j/SpringResilienceRouteOkTest.java  |  44 +++++
 .../src/test/resources/log4j2.properties           |  28 +++
 .../BlueprintResilienceRouteFallbackTest.xml       |  41 +++++
 .../BlueprintResilienceRouteOkTest.xml             |  47 +++++
 .../SpringHystrixRouteConfigMaximumSizeTest.xml    |  49 +++++
 .../SpringHystrixRouteConfigRefTest.xml            |  51 ++++++
 .../resilience4j/SpringHystrixRouteConfigTest.xml  |  49 +++++
 .../SpringResilienceRouteFallbackTest.xml          |  42 +++++
 .../resilience4j/SpringResilienceRouteOkTest.xml   |  48 +++++
 .../camel-resilience4j-starter/pom.xml             |  53 ++++++
 .../src/main/resources/META-INF/LICENSE.txt        | 203 +++++++++++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt         |  11 ++
 .../src/main/resources/META-INF/spring.provides    |  17 ++
 platforms/spring-boot/components-starter/pom.xml   |   1 +
 36 files changed, 2074 insertions(+)

diff --git a/components/camel-resilience4j/pom.xml b/components/camel-resilience4j/pom.xml
new file mode 100644
index 0000000..fa396b4
--- /dev/null
+++ b/components/camel-resilience4j/pom.xml
@@ -0,0 +1,81 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-resilience4j</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel :: Resilience4j</name>
+    <description>Circuit Breaker EIP using Resilience4j</description>
+
+    <properties>
+        <firstVersion>3.0.0</firstVersion>
+        <label>eip,microservice</label>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core-engine</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.github.resilience4j</groupId>
+            <artifactId>resilience4j-circuitbreaker</artifactId>
+            <version>1.1.0</version>
+        </dependency>
+
+        <!-- for testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-blueprint</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/components/camel-resilience4j/src/main/docs/resilience4j.adoc b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
new file mode 100644
index 0000000..9afc96e
--- /dev/null
+++ b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
@@ -0,0 +1,49 @@
+= Hystrix Component
+
+*Since Camel 2.18*
+
+The Hystrix component integrates Netflix Hystrix circuit breaker in Camel routes.
+
+For more details see the Hystrix EIP documentation.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-hystrix</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+----
+
+// spring-boot-auto-configure options: START
+== Spring Boot Auto-Configuration
+
+When using Spring Boot make sure to use the following Maven dependency to have support for auto configuration:
+
+[source,xml]
+----
+<dependency>
+  <groupId>org.apache.camel</groupId>
+  <artifactId>camel-hystrix-starter</artifactId>
+  <version>x.x.x</version>
+  <!-- use the same version as your Camel core version -->
+</dependency>
+----
+
+
+The component supports 3 options, which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *camel.component.hystrix.mapping.enabled* | Enables the automatic mapping of the hystrics metric servlet into the Spring web context. | true | Boolean
+| *camel.component.hystrix.mapping.path* | Endpoint for hystrix metrics servlet. | /hystrix.stream | String
+| *camel.component.hystrix.mapping.servlet-name* | Name of the Hystrix metrics servlet. | HystrixEventStreamServlet | String
+|===
+// spring-boot-auto-configure options: END
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
new file mode 100644
index 0000000..0dcbb0c
--- /dev/null
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
@@ -0,0 +1,29 @@
+/*
+ * 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.component.resilience4j;
+
+// TODO: Make these as generic constants so we can use it for hystrix and resilience4j
+
+public interface CircuitBreakerConstants {
+
+    String RESPONSE_SUCCESSFUL_EXECUTION = "CamelCircuitBreakerSuccessfulExecution";
+    String RESPONSE_FROM_FALLBACK = "CamelCircuitBreakerResponseFromFallback";
+    String RESPONSE_SHORT_CIRCUITED = "CamelCircuitBreakerResponseShortCircuited";
+    String RESPONSE_TIMED_OUT = "CamelCircuitBreakerResponseTimedOut";
+    String RESPONSE_REJECTED = "CamelCircuitBreakerResponseRejected";
+
+}
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
new file mode 100644
index 0000000..a9bd0e7
--- /dev/null
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -0,0 +1,165 @@
+/*
+ * 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.component.resilience4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreaker;
+import io.vavr.control.Try;
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.Navigate;
+import org.apache.camel.Processor;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.IdAware;
+import org.apache.camel.support.AsyncProcessorSupport;
+import org.apache.camel.support.ExchangeHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of Circuit Breaker EIP using resilience4j.
+ */
+@ManagedResource(description = "Managed Resilience Processor")
+public class ResilienceProcessor extends AsyncProcessorSupport implements Navigate<Processor>, org.apache.camel.Traceable, IdAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ResilienceProcessor.class);
+
+    private String id;
+    private final Processor processor;
+    private final Processor fallback;
+    private final boolean fallbackViaNetwork;
+
+    public ResilienceProcessor(Processor processor, Processor fallback, boolean fallbackViaNetwork) {
+        this.processor = processor;
+        this.fallback = fallback;
+        this.fallbackViaNetwork = fallbackViaNetwork;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getTraceLabel() {
+        return "resilience4j";
+    }
+
+    @Override
+    public List<Processor> next() {
+        if (!hasNext()) {
+            return null;
+        }
+        List<Processor> answer = new ArrayList<>();
+        answer.add(processor);
+        if (fallback != null) {
+            answer.add(fallback);
+        }
+        return answer;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return true;
+    }
+
+    @Override
+    public boolean process(Exchange exchange, AsyncCallback callback) {
+        // run this as if we run inside try .. catch so there is no regular Camel error handler
+        exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true);
+
+        CircuitBreaker cb = CircuitBreaker.ofDefaults(id);
+
+        Callable task = CircuitBreaker.decorateCallable(cb, () -> {
+            try {
+                LOG.debug("Running processor: {} with exchange: {}", processor, exchange);
+                // prepare a copy of exchange so downstream processors don't cause side-effects if they mutate the exchange
+                // in case timeout processing and continue with the fallback etc
+                Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false, false);
+                // process the processor until its fully done
+                processor.process(copy);
+                if (copy.getException() != null) {
+                    exchange.setException(copy.getException());
+                } else {
+                    // copy the result as its regarded as success
+                    ExchangeHelper.copyResults(exchange, copy);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+                }
+            } catch (Throwable e) {
+                exchange.setException(e);
+            }
+            if (exchange.getException() != null) {
+                // throw exception so resilient4j know it was a failure
+                throw exchange.getException();
+            }
+            return null;
+        });
+
+        Try.ofCallable(task)
+                .recover(f -> {
+                    if (fallback != null) {
+                        // store the last to endpoint as the failure endpoint
+                        if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
+                            exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
+                        }
+                        // give the rest of the pipeline another chance
+                        exchange.setProperty(Exchange.EXCEPTION_HANDLED, true);
+                        exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException());
+                        exchange.removeProperty(Exchange.ROUTE_STOP);
+                        exchange.setException(null);
+                        // and we should not be regarded as exhausted as we are in a try .. catch block
+                        exchange.removeProperty(Exchange.REDELIVERY_EXHAUSTED);
+                        // run the fallback processor
+                        try {
+                            LOG.debug("Running fallback: {} with exchange: {}", fallback, exchange);
+                            // process the fallback until its fully done
+                            fallback.process(exchange);
+                            LOG.debug("Running fallback: {} with exchange: {} done", fallback, exchange);
+                        } catch (Exception e) {
+                            exchange.setException(e);
+                        }
+
+                        exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+                        exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+                    }
+                    return null;
+                })
+                .andFinally(() -> callback.done(false)).get();
+
+        return false;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        // noop
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // noop
+    }
+
+}
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessorFactory.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessorFactory.java
new file mode 100644
index 0000000..7da89e8
--- /dev/null
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessorFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.Processor;
+import org.apache.camel.impl.engine.TypedProcessorFactory;
+import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.spi.RouteContext;
+
+/**
+ * To integrate camel-resilience4j with the Camel routes using the Circuit Breaker EIP.
+ */
+public class ResilienceProcessorFactory extends TypedProcessorFactory<CircuitBreakerDefinition> {
+
+    public ResilienceProcessorFactory() {
+        super(CircuitBreakerDefinition.class);
+    }
+
+    @Override
+    public Processor doCreateProcessor(RouteContext routeContext, CircuitBreakerDefinition definition) throws Exception {
+        return new ResilienceReifier(definition).createProcessor(routeContext);
+    }
+
+}
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
new file mode 100644
index 0000000..1a07f57
--- /dev/null
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.Processor;
+import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.reifier.ProcessorReifier;
+import org.apache.camel.spi.RouteContext;
+
+public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
+
+    public ResilienceReifier(CircuitBreakerDefinition definition) {
+        super(definition);
+    }
+
+    @Override
+    public Processor createProcessor(RouteContext routeContext) throws Exception {
+        // create the regular and fallback processors
+        Processor processor = createChildProcessor(routeContext, true);
+        Processor fallback = null;
+        if (definition.getOnFallback() != null) {
+            fallback = ProcessorReifier.reifier(definition.getOnFallback()).createProcessor(routeContext);
+        }
+
+        final String id = getId(definition, routeContext);
+
+        return new ResilienceProcessor(processor, fallback, false);
+    }
+
+}
diff --git a/components/camel-resilience4j/src/main/resources/META-INF/services/org/apache/camel/model/CircuitBreakerDefinition b/components/camel-resilience4j/src/main/resources/META-INF/services/org/apache/camel/model/CircuitBreakerDefinition
new file mode 100644
index 0000000..bab3802
--- /dev/null
+++ b/components/camel-resilience4j/src/main/resources/META-INF/services/org/apache/camel/model/CircuitBreakerDefinition
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.resilience4j.ResilienceProcessorFactory
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java
new file mode 100644
index 0000000..0dac4de
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
+import org.junit.Test;
+
+public class BlueprintResilienceRouteFallbackTest extends CamelBlueprintTestSupport {
+
+    @Override
+    protected String getBlueprintDescriptor() {
+        return "org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.xml";
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java
new file mode 100644
index 0000000..5f064b3
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
+import org.junit.Test;
+
+public class BlueprintResilienceRouteOkTest extends CamelBlueprintTestSupport {
+
+    @Override
+    protected String getBlueprintDescriptor() {
+        return "org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.xml";
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java
new file mode 100644
index 0000000..e9e7bcf
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.component.resilience4j;
+
+import java.io.IOException;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.resilience4j.CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED;
+import static org.apache.camel.component.resilience4j.CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION;
+
+@Ignore
+public class HystrixCircuitOpenTest extends CamelTestSupport {
+    public static final Integer REQUEST_VOLUME_THRESHOLD = 4;
+    private static final Logger LOG = LoggerFactory.getLogger(HystrixCircuitOpenTest.class);
+
+    private HystrixExceptionRoute route = new HystrixExceptionRoute();
+
+    @Test
+    public void testCircuitOpen() throws Exception {
+        LOG.info("testCircuitOpen start");
+        // failing requests
+        route.throwException = true;
+        for (int i = 0; i < 2 * REQUEST_VOLUME_THRESHOLD; i++) {
+            try {
+                template.asyncRequestBody("direct:start", "Request Body");
+            } catch (CamelExecutionException e) {
+                LOG.info(e.toString());
+            }
+        }
+        Thread.sleep(1500);
+
+        resetMocks();
+
+        // notice this can be flaky due timing when using thread sleeps in unit tests
+        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SHORT_CIRCUITED, true);
+
+        route.throwException = false;
+        try {
+            template.requestBody("direct:start", "Request Body");
+            LOG.info("Instead circuit open expected");
+        } catch (CamelExecutionException e) {
+            LOG.info("Circuit open expected ", e);
+        }
+
+        assertMockEndpointsSatisfied();
+
+        // wait for the circuit to try an other request
+        Thread.sleep(500);
+        for (int i = 0; i < 2 * REQUEST_VOLUME_THRESHOLD; i++) {
+            try {
+                template.requestBody("direct:start", "Request Body");
+                LOG.info("Circuit has closed");
+            } catch (CamelExecutionException e) {
+                Thread.sleep(i * 100);
+                LOG.info("Circuit will be closed soon " + e.toString());
+            }
+        }
+
+        resetMocks();
+
+        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SHORT_CIRCUITED, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SUCCESSFUL_EXECUTION, true);
+
+        template.requestBody("direct:start", "Request Body");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return route;
+    }
+
+    class HystrixExceptionRoute extends RouteBuilder {
+        volatile boolean throwException = true;
+
+        @Override
+        public void configure() throws Exception {
+            from("direct:start")
+                .circuitBreaker()
+                    .hystrixConfiguration()
+                        .executionTimeoutInMilliseconds(100)
+                        .circuitBreakerRequestVolumeThreshold(REQUEST_VOLUME_THRESHOLD)
+                        .metricsRollingStatisticalWindowInMilliseconds(1000)
+                        .circuitBreakerSleepWindowInMilliseconds(2000)
+                    .end()
+                    .log("Hystrix processing start: ${threadName}")
+                    .process(new Processor() {
+                        @Override
+                        public void process(Exchange exchange) throws Exception {
+                            if (throwException) {
+                                LOG.info("Will throw exception");
+                                throw new IOException("Route has failed");
+                            } else {
+                                LOG.info("Will NOT throw exception");
+                            }
+                        }
+                    })
+                    .log("Hystrix processing end: ${threadName}")
+                .end()
+                .log(RESPONSE_SHORT_CIRCUITED + " = ${exchangeProperty." + RESPONSE_SHORT_CIRCUITED + "}")
+                .to("mock:result");
+        }
+    }
+}
+
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java
new file mode 100644
index 0000000..d50e02d
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class HystrixInheritErrorHandlerTest extends CamelTestSupport {
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:a").expectedMessageCount(3 + 1);
+        getMockEndpoint("mock:dead").expectedMessageCount(1);
+        getMockEndpoint("mock:result").expectedMessageCount(0);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDelay(0));
+
+                from("direct:start")
+                    .to("log:start")
+                    // turn on Camel's error handler on hystrix so it can do redeliveries
+                    .circuitBreaker().inheritErrorHandler(true)
+                        .to("mock:a")
+                        .throwException(new IllegalArgumentException("Forced"))
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java
new file mode 100644
index 0000000..cc225fe
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.model.HystrixConfigurationDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class HystrixRouteConfigMaximumSizeTest extends CamelTestSupport {
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+    
+    @Test
+    public void testGroupKeyAndThreadPoolKeyConfigFlagsDoNotScrapHystrixConfiguration() throws Exception {
+        // dummy route
+        RouteBuilder rb = new RouteBuilder(context) {
+            @Override
+            public void configure() throws Exception {
+                from("direct:foo")
+                    .circuitBreaker()
+                        .hystrixConfiguration().groupKey("test2").metricsHealthSnapshotIntervalInMilliseconds(99999).end()
+                        .to("log:hello")
+                    .end();
+                
+            }
+        };
+        
+        rb.configure();
+        
+        RouteDefinition route = rb.getRouteCollection().getRoutes().get(0);
+        assertEquals(CircuitBreakerDefinition.class, route.getOutputs().get(0).getClass());
+        
+        HystrixConfigurationDefinition config = ((CircuitBreakerDefinition) route.getOutputs().get(0)).getHystrixConfiguration();
+        assertEquals("test2", config.getGroupKey());
+        assertEquals(99999, config.getMetricsHealthSnapshotIntervalInMilliseconds().intValue());
+    }
+    
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                        .hystrixConfiguration().groupKey("myCamelApp").requestLogEnabled(false).corePoolSize(5)
+                            .maximumSize(15).allowMaximumSizeToDivergeFromCoreSize(true)
+                        .end()
+                        .to("direct:foo")
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("mock:result");
+
+                from("direct:foo")
+                    .transform().constant("Bye World");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.java
new file mode 100644
index 0000000..dc47a32
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.model.HystrixConfigurationDefinition;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class HystrixRouteConfigTest extends CamelTestSupport {
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+    
+    @Test
+    public void testGroupKeyAndThreadPoolKeyConfigFlagsDoNotScrapHystrixConfiguration() throws Exception {
+        // dummy route
+        RouteBuilder rb = new RouteBuilder(context) {
+            @Override
+            public void configure() throws Exception {
+                from("direct:foo")
+                    .circuitBreaker()
+                        .hystrixConfiguration().groupKey("test2").metricsHealthSnapshotIntervalInMilliseconds(99999).end()
+                        .to("log:hello")
+                    .end();
+                
+            }
+        };
+        
+        rb.configure();
+        
+        RouteDefinition route = rb.getRouteCollection().getRoutes().get(0);
+        assertEquals(CircuitBreakerDefinition.class, route.getOutputs().get(0).getClass());
+        
+        HystrixConfigurationDefinition config = ((CircuitBreakerDefinition) route.getOutputs().get(0)).getHystrixConfiguration();
+        assertEquals("test2", config.getGroupKey());
+        assertEquals(99999, config.getMetricsHealthSnapshotIntervalInMilliseconds().intValue());
+    }
+
+    
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                        .hystrixConfiguration().groupKey("myCamelApp").requestLogEnabled(false).corePoolSize(5).end()
+                        .to("direct:foo")
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("mock:result");
+
+                from("direct:foo")
+                    .transform().constant("Bye World");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
new file mode 100644
index 0000000..7f2ea21
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore
+public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to("log:start")
+                    .circuitBreaker()
+                        .throwException(new IllegalArgumentException("Forced"))
+                    .onFallbackViaNetwork()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java
new file mode 100644
index 0000000..63abdba
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.component.resilience4j;
+
+import java.util.concurrent.TimeoutException;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Hystrix using timeout with Java DSL
+ */
+@Ignore
+public class HystrixTimeoutTest extends CamelTestSupport {
+
+    @Test
+    public void testFast() throws Exception {
+        // this calls the fast route and therefore we get a response
+        Object out = template.requestBody("direct:start", "fast");
+        assertEquals("Fast response", out);
+    }
+
+    @Test
+    public void testSlow() throws Exception {
+        // this calls the slow route and therefore causes a timeout which triggers an exception
+        try {
+            template.requestBody("direct:start", "slow");
+            fail("Should fail due to timeout");
+        } catch (Exception e) {
+            // expected a timeout
+            assertIsInstanceOf(TimeoutException.class, e.getCause().getCause());
+        }
+    }
+
+    @Test
+    public void testSlowLoop() throws Exception {
+        // this calls the slow route and therefore causes a timeout which triggers an exception
+        for (int i = 0; i < 10; i++) {
+            try {
+                log.info(">>> test run " + i + " <<<");
+                template.requestBody("direct:start", "slow");
+                fail("Should fail due to timeout");
+            } catch (Exception e) {
+                // expected a timeout
+                assertIsInstanceOf(TimeoutException.class, e.getCause().getCause());
+            }
+        }
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                        // use 2 second timeout
+                        .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
+                        .log("Hystrix processing start: ${threadName}")
+                        .toD("direct:${body}")
+                        .log("Hystrix processing end: ${threadName}")
+                    .end()
+                    .log("After Hystrix ${body}");
+
+                from("direct:fast")
+                    // this is a fast route and takes 1 second to respond
+                    .log("Fast processing start: ${threadName}")
+                    .delay(1000)
+                    .transform().constant("Fast response")
+                    .log("Fast processing end: ${threadName}");
+
+                from("direct:slow")
+                    // this is a slow route and takes 3 second to respond
+                    .log("Slow processing start: ${threadName}")
+                    .delay(3000)
+                    .transform().constant("Slow response")
+                    .log("Slow processing end: ${threadName}");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.java
new file mode 100644
index 0000000..9a8bb67
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.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.component.resilience4j;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Hystrix using timeout and fallback with Java DSL
+ */
+@Ignore
+public class HystrixTimeoutWithFallbackTest extends CamelTestSupport {
+
+    @Test
+    public void testFast() throws Exception {
+        // this calls the fast route and therefore we get a response
+        Object out = template.requestBody("direct:start", "fast");
+        assertEquals("LAST CHANGE", out);
+    }
+
+    @Test
+    public void testSlow() throws Exception {
+        // this calls the slow route and therefore causes a timeout which triggers the fallback
+        Object out = template.requestBody("direct:start", "slow");
+        assertEquals("LAST CHANGE", out);
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                    // use 2 second timeout
+                    .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
+                        .log("Hystrix processing start: ${threadName}")
+                        .toD("direct:${body}")
+                        .log("Hystrix processing end: ${threadName}")
+                    .onFallback()
+                        // use fallback if there was an exception or timeout
+                        .log("Hystrix fallback start: ${threadName}")
+                        .transform().constant("Fallback response")
+                        .log("Hystrix fallback end: ${threadName}")
+                    .end()
+                    .log("After Hystrix ${body}")
+                    .transform(simple("A CHANGE"))
+                    .transform(simple("LAST CHANGE"))
+                    .log("End ${body}");
+
+                from("direct:fast")
+                    // this is a fast route and takes 1 second to respond
+                    .log("Fast processing start: ${threadName}")
+                    .delay(1000)
+                    .transform().constant("Fast response")
+                    .log("Fast processing end: ${threadName}");
+
+                from("direct:slow")
+                    // this is a slow route and takes 3 second to respond
+                    .log("Slow processing start: ${threadName}")
+                    .delay(3000)
+                    .transform().constant("Slow response")
+                    .log("Slow processing end: ${threadName}");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java
new file mode 100644
index 0000000..6ae5c36
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ResilienceRouteFallbackTest extends CamelTestSupport {
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .to("log:start")
+                    .circuitBreaker()
+                        .throwException(new IllegalArgumentException("Forced"))
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java
new file mode 100644
index 0000000..891d504
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ResilienceRouteOkTest extends CamelTestSupport {
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                        .to("direct:foo")
+                        .to("log:foo")
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+
+                from("direct:foo")
+                    .transform().constant("Bye World");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java
new file mode 100644
index 0000000..fabd88a
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+
+@Ignore
+@DirtiesContext
+public class SpringHystrixRouteConfigMaximumSizeTest extends CamelSpringTestSupport {
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigMaximumSizeTest.xml");
+    }
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java
new file mode 100644
index 0000000..14eaae3
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+
+@Ignore
+@DirtiesContext
+public class SpringHystrixRouteConfigRefTest extends CamelSpringTestSupport {
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigRefTest.xml");
+    }
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java
new file mode 100644
index 0000000..72ec426
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+
+@Ignore
+@DirtiesContext
+public class SpringHystrixRouteConfigTest extends CamelSpringTestSupport {
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigTest.xml");
+    }
+
+    @Test
+    public void testHystrix() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java
new file mode 100644
index 0000000..12792ad
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+public class SpringResilienceRouteFallbackTest extends CamelSpringTestSupport {
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.xml");
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java
new file mode 100644
index 0000000..c305804
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.resilience4j;
+
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+public class SpringResilienceRouteOkTest extends CamelSpringTestSupport {
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.xml");
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/resources/log4j2.properties b/components/camel-resilience4j/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..3e584b4
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-resilience4j-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.xml
new file mode 100644
index 0000000..9b1b683
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.xml
@@ -0,0 +1,41 @@
+<?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.
+
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xsi:schemaLocation="
+             http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+  <camelContext id="myCamel" xmlns="http://camel.apache.org/schema/blueprint">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <throwException exceptionType="java.lang.IllegalArgumentException" message="Forced"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+  </camelContext>
+
+</blueprint>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.xml
new file mode 100644
index 0000000..4c55703
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.xml
@@ -0,0 +1,47 @@
+<?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.
+
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xsi:schemaLocation="
+             http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+  <camelContext id="myCamel" xmlns="http://camel.apache.org/schema/blueprint">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <to uri="direct:foo"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+    <route>
+      <from uri="direct:foo"/>
+      <transform>
+        <constant>Bye World</constant>
+      </transform>
+    </route>
+  </camelContext>
+
+</blueprint>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml
new file mode 100644
index 0000000..4d0aa78
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml
@@ -0,0 +1,49 @@
+<?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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <hystrixConfiguration groupKey="myCamelApp" requestLogEnabled="false" corePoolSize="5" maximumSize="15" allowMaximumSizeToDivergeFromCoreSize="true"/>
+        <to uri="direct:foo"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+    <route>
+      <from uri="direct:foo"/>
+      <transform>
+        <constant>Bye World</constant>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml
new file mode 100644
index 0000000..40cdf25
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml
@@ -0,0 +1,51 @@
+<?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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+    <hystrixConfiguration id="hysConfig" requestLogEnabled="false" corePoolSize="5"/>
+
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker configurationRef="hysConfig">
+        <to uri="direct:foo"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+    <route>
+      <from uri="direct:foo"/>
+      <transform>
+        <constant>Bye World</constant>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml
new file mode 100644
index 0000000..2c8a9a6
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml
@@ -0,0 +1,49 @@
+<?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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <hystrixConfiguration groupKey="myCamelApp" requestLogEnabled="false" corePoolSize="5"/>
+        <to uri="direct:foo"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+    <route>
+      <from uri="direct:foo"/>
+      <transform>
+        <constant>Bye World</constant>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.xml
new file mode 100644
index 0000000..39dbe97
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.xml
@@ -0,0 +1,42 @@
+<?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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <throwException exceptionType="java.lang.IllegalArgumentException" message="Forced"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+  </camelContext>
+
+</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.xml
new file mode 100644
index 0000000..1e2b139
--- /dev/null
+++ b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.xml
@@ -0,0 +1,48 @@
+<?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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:start"/>
+      <circuitBreaker>
+        <to uri="direct:foo"/>
+        <onFallback>
+          <transform>
+            <constant>Fallback message</constant>
+          </transform>
+        </onFallback>
+      </circuitBreaker>
+      <to uri="mock:result"/>
+    </route>
+
+    <route>
+      <from uri="direct:foo"/>
+      <transform>
+        <constant>Bye World</constant>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>
\ No newline at end of file
diff --git a/platforms/spring-boot/components-starter/camel-resilience4j-starter/pom.xml b/platforms/spring-boot/components-starter/camel-resilience4j-starter/pom.xml
new file mode 100644
index 0000000..0782fb2
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/pom.xml
@@ -0,0 +1,53 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components-starter</artifactId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>camel-resilience4j-starter</artifactId>
+  <packaging>jar</packaging>
+  <name>Spring-Boot Starter :: Camel :: Resilience4j</name>
+  <description>Spring-Boot Starter for Circuit Breaker EIP using Resilience4j</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+      <version>${spring-boot-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-resilience4j</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <!--START OF GENERATED CODE-->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-boot-starter</artifactId>
+    </dependency>
+    <!--END OF GENERATED CODE-->
+  </dependencies>
+</project>
diff --git a/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/LICENSE.txt b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/NOTICE.txt b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.provides b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.provides
new file mode 100644
index 0000000..213b910
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+provides: camel-resilience4j
diff --git a/platforms/spring-boot/components-starter/pom.xml b/platforms/spring-boot/components-starter/pom.xml
index e083e0f..d04c684 100644
--- a/platforms/spring-boot/components-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/pom.xml
@@ -313,6 +313,7 @@
     <module>camel-reactive-streams-starter</module>
     <module>camel-reactor-starter</module>
     <module>camel-ref-starter</module>
+    <module>camel-resilience4j-starter</module>
     <module>camel-rest-starter</module>
     <module>camel-rest-swagger-starter</module>
     <module>camel-ribbon-starter</module>


[camel] 19/23: CAMEL-14186: camel-core-starter - Spring Boot auto-configuration is not generated for some models

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f1bd476dafe5a59d30434aedee2f0b3b13d016e0
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 07:08:16 2019 +0100

    CAMEL-14186: camel-core-starter - Spring Boot auto-configuration is not generated for some models
---
 .../RestConfigurationDefinitionProperties.java     |  10 +-
 .../Resilience4jConfigurationDefinitionCommon.java | 219 +++++++++++++++++++++
 ...ilience4jConfigurationDefinitionProperties.java |  50 +++++
 .../packaging/SpringBootAutoConfigurationMojo.java |  45 +++--
 4 files changed, 299 insertions(+), 25 deletions(-)

diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/rest/springboot/RestConfigurationDefinitionProperties.java b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/rest/springboot/RestConfigurationDefinitionProperties.java
index 7cebfff..5111217 100644
--- a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/rest/springboot/RestConfigurationDefinitionProperties.java
+++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/rest/springboot/RestConfigurationDefinitionProperties.java
@@ -33,11 +33,11 @@ public class RestConfigurationDefinitionProperties {
 
     /**
      * The Camel Rest component to use for the REST transport (consumer), such
-     * as netty-http, jetty, servlet, undertow. If no component has been explicit configured,
-     * then Camel will lookup if there is a Camel component that integrates with
-     * the Rest DSL, or if a org.apache.camel.spi.RestConsumerFactory is
-     * registered in the registry. If either one is found, then that is being
-     * used.
+     * as netty-http, jetty, servlet, undertow. If no component has been
+     * explicit configured, then Camel will lookup if there is a Camel component
+     * that integrates with the Rest DSL, or if a
+     * org.apache.camel.spi.RestConsumerFactory is registered in the registry.
+     * If either one is found, then that is being used.
      */
     private String component;
     /**
diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionCommon.java b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionCommon.java
new file mode 100644
index 0000000..b9ecfda
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionCommon.java
@@ -0,0 +1,219 @@
+/*
+ * 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.model.springboot;
+
+import javax.annotation.Generated;
+
+/**
+ * Resilience4j Circuit Breaker EIP configuration
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+public class Resilience4jConfigurationDefinitionCommon {
+
+    /**
+     * Refers to an existing
+     * io.github.resilience4j.circuitbreaker.CircuitBreaker instance to lookup
+     * and use from the registry. When using this, then any other circuit
+     * breaker options are not in use.
+     */
+    private String circuitBreakerRef;
+    /**
+     * Refers to an existing
+     * io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to
+     * lookup and use from the registry.
+     */
+    private String configRef;
+    /**
+     * Configures the failure rate threshold in percentage. If the failure rate
+     * is equal or greater than the threshold the CircuitBreaker transitions to
+     * open and starts short-circuiting calls. The threshold must be greater
+     * than 0 and not greater than 100. Default value is 50 percentage.
+     */
+    private Float failureRateThreshold;
+    /**
+     * Configures the number of permitted calls when the CircuitBreaker is half
+     * open. The size must be greater than 0. Default size is 10.
+     */
+    private Integer permittedNumberOfCallsInHalfOpenState = 10;
+    /**
+     * Configures the size of the sliding window which is used to record the
+     * outcome of calls when the CircuitBreaker is closed. slidingWindowSize
+     * configures the size of the sliding window. Sliding window can either be
+     * count-based or time-based. If slidingWindowType is COUNT_BASED, the last
+     * slidingWindowSize calls are recorded and aggregated. If slidingWindowType
+     * is TIME_BASED, the calls of the last slidingWindowSize seconds are
+     * recorded and aggregated. The slidingWindowSize must be greater than 0.
+     * The minimumNumberOfCalls must be greater than 0. If the slidingWindowType
+     * is COUNT_BASED, the minimumNumberOfCalls cannot be greater than
+     * slidingWindowSize. If the slidingWindowType is TIME_BASED, you can pick
+     * whatever you want. Default slidingWindowSize is 100.
+     */
+    private Integer slidingWindowSize = 100;
+    /**
+     * Configures the type of the sliding window which is used to record the
+     * outcome of calls when the CircuitBreaker is closed. Sliding window can
+     * either be count-based or time-based. If slidingWindowType is COUNT_BASED,
+     * the last slidingWindowSize calls are recorded and aggregated. If
+     * slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize
+     * seconds are recorded and aggregated. Default slidingWindowType is
+     * COUNT_BASED.
+     */
+    private String slidingWindowType = "COUNT_BASED";
+    /**
+     * Configures configures the minimum number of calls which are required (per
+     * sliding window period) before the CircuitBreaker can calculate the error
+     * rate. For example, if minimumNumberOfCalls is 10, then at least 10 calls
+     * must be recorded, before the failure rate can be calculated. If only 9
+     * calls have been recorded the CircuitBreaker will not transition to open
+     * even if all 9 calls have failed. Default minimumNumberOfCalls is 100
+     */
+    private Integer minimumNumberOfCalls = 100;
+    /**
+     * Enables writable stack traces. When set to false, Exception.getStackTrace
+     * returns a zero length array. This may be used to reduce log spam when the
+     * circuit breaker is open as the cause of the exceptions is already known
+     * (the circuit breaker is short-circuiting calls).
+     */
+    private Boolean writableStackTraceEnabled = true;
+    /**
+     * Configures the wait duration (in seconds) which specifies how long the
+     * CircuitBreaker should stay open, before it switches to half open. Default
+     * value is 60 seconds.
+     */
+    private Integer waitDurationInOpenState = 60;
+    /**
+     * Enables automatic transition from OPEN to HALF_OPEN state once the
+     * waitDurationInOpenState has passed.
+     */
+    private Boolean automaticTransitionFromOpenToHalfOpenEnabled = false;
+    /**
+     * Configures a threshold in percentage. The CircuitBreaker considers a call
+     * as slow when the call duration is greater than
+     * slowCallDurationThreshold(Duration. When the percentage of slow calls is
+     * equal or greater the threshold, the CircuitBreaker transitions to open
+     * and starts short-circuiting calls. The threshold must be greater than 0
+     * and not greater than 100. Default value is 100 percentage which means
+     * that all recorded calls must be slower than slowCallDurationThreshold.
+     */
+    private Float slowCallRateThreshold;
+    /**
+     * Configures the duration threshold (seconds) above which calls are
+     * considered as slow and increase the slow calls percentage. Default value
+     * is 60 seconds.
+     */
+    private Integer slowCallDurationThreshold = 60;
+
+    public String getCircuitBreakerRef() {
+        return circuitBreakerRef;
+    }
+
+    public void setCircuitBreakerRef(String circuitBreakerRef) {
+        this.circuitBreakerRef = circuitBreakerRef;
+    }
+
+    public String getConfigRef() {
+        return configRef;
+    }
+
+    public void setConfigRef(String configRef) {
+        this.configRef = configRef;
+    }
+
+    public Float getFailureRateThreshold() {
+        return failureRateThreshold;
+    }
+
+    public void setFailureRateThreshold(Float failureRateThreshold) {
+        this.failureRateThreshold = failureRateThreshold;
+    }
+
+    public Integer getPermittedNumberOfCallsInHalfOpenState() {
+        return permittedNumberOfCallsInHalfOpenState;
+    }
+
+    public void setPermittedNumberOfCallsInHalfOpenState(
+            Integer permittedNumberOfCallsInHalfOpenState) {
+        this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState;
+    }
+
+    public Integer getSlidingWindowSize() {
+        return slidingWindowSize;
+    }
+
+    public void setSlidingWindowSize(Integer slidingWindowSize) {
+        this.slidingWindowSize = slidingWindowSize;
+    }
+
+    public String getSlidingWindowType() {
+        return slidingWindowType;
+    }
+
+    public void setSlidingWindowType(String slidingWindowType) {
+        this.slidingWindowType = slidingWindowType;
+    }
+
+    public Integer getMinimumNumberOfCalls() {
+        return minimumNumberOfCalls;
+    }
+
+    public void setMinimumNumberOfCalls(Integer minimumNumberOfCalls) {
+        this.minimumNumberOfCalls = minimumNumberOfCalls;
+    }
+
+    public Boolean getWritableStackTraceEnabled() {
+        return writableStackTraceEnabled;
+    }
+
+    public void setWritableStackTraceEnabled(Boolean writableStackTraceEnabled) {
+        this.writableStackTraceEnabled = writableStackTraceEnabled;
+    }
+
+    public Integer getWaitDurationInOpenState() {
+        return waitDurationInOpenState;
+    }
+
+    public void setWaitDurationInOpenState(Integer waitDurationInOpenState) {
+        this.waitDurationInOpenState = waitDurationInOpenState;
+    }
+
+    public Boolean getAutomaticTransitionFromOpenToHalfOpenEnabled() {
+        return automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    public void setAutomaticTransitionFromOpenToHalfOpenEnabled(
+            Boolean automaticTransitionFromOpenToHalfOpenEnabled) {
+        this.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    public Float getSlowCallRateThreshold() {
+        return slowCallRateThreshold;
+    }
+
+    public void setSlowCallRateThreshold(Float slowCallRateThreshold) {
+        this.slowCallRateThreshold = slowCallRateThreshold;
+    }
+
+    public Integer getSlowCallDurationThreshold() {
+        return slowCallDurationThreshold;
+    }
+
+    public void setSlowCallDurationThreshold(Integer slowCallDurationThreshold) {
+        this.slowCallDurationThreshold = slowCallDurationThreshold;
+    }
+}
\ No newline at end of file
diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionProperties.java b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionProperties.java
new file mode 100644
index 0000000..dcc6b32
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/model/springboot/Resilience4jConfigurationDefinitionProperties.java
@@ -0,0 +1,50 @@
+/*
+ * 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.model.springboot;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Generated;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+@ConfigurationProperties(prefix = "camel.resilience4j")
+public class Resilience4jConfigurationDefinitionProperties
+        extends
+            Resilience4jConfigurationDefinitionCommon {
+
+    /**
+     * Enable the component
+     */
+    private boolean enabled = true;
+    /**
+     * Define additional configuration definitions
+     */
+    private Map<String, Resilience4jConfigurationDefinitionCommon> configurations = new HashMap<>();
+
+    public Map<String, Resilience4jConfigurationDefinitionCommon> getConfigurations() {
+        return configurations;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+}
\ No newline at end of file
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
index 32d6dce..e7257d8 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java
@@ -197,7 +197,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
         }
 
         // Spring-boot configuration has been moved on starters
-        File starterDir = SpringBootHelper.starterDir(baseDir, project.getArtifactId());
+        File starterDir = SpringBootHelper.starterDir(baseDir, getStarterArtifactId());
         if (!starterDir.exists() || !(new File(starterDir, "pom.xml").exists())) {
             // If the starter does not exist, no configuration can be created
             getLog().info("Component auto-configuration will not be created: the starter does not exist");
@@ -209,9 +209,13 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
 
     private void executeAll() throws MojoExecutionException, MojoFailureException {
         Map<File, Supplier<String>> files = PackageHelper.findJsonFiles(buildDir, p -> p.isDirectory() || p.getName().endsWith(".json")).stream()
-            .collect(Collectors.toMap(Function.identity(), s -> cache(() -> loadJson(s))));
+                .collect(Collectors.toMap(Function.identity(), s -> cache(() -> loadJson(s))));
+
+        // special for camel-core-engine where we generate some special auto-configuration source code
+        if ("camel-core-engine".equals(project.getArtifactId())) {
+            executeModels(files);
+        }
 
-        executeModels(files);
         executeComponent(files);
         executeDataFormat(files);
         executeLanguage(files);
@@ -250,8 +254,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-hystrix-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.hystrix", true);
         }
 
@@ -263,8 +266,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-resilience4j-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.resilience4j", true);
         }
 
@@ -276,8 +278,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-consul-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.cloud.consul.service-discovery", true);
         }
 
@@ -289,8 +290,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-dns-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.cloud.dns.service-discovery", true);
         }
 
@@ -302,8 +302,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-etcd-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.cloud.etcd.service-discovery", true);
         }
 
@@ -328,8 +327,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-kubernetes-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createOtherModelConfigurationSource(pkg, model, "camel.cloud.ribbon.load-balancer", true);
         }
 
@@ -341,8 +339,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
             int pos = model.getJavaType().lastIndexOf(".");
             String pkg = model.getJavaType().substring(0, pos) + ".springboot";
 
-            // Generate properties, auto-configuration happens in
-            // camel-kubernetes-starter
+            // Generate properties, auto-configuration for camel-core-starter
             createRestConfigurationSource(pkg, model, "camel.rest");
             createRestModuleAutoConfigurationSource(pkg, model);
         }
@@ -2178,7 +2175,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
 
     private void writeSourceIfChanged(String source, String fileName) throws MojoFailureException {
 
-        File target = new File(SpringBootHelper.starterSrcDir(baseDir, project.getArtifactId()), fileName);
+        File target = new File(SpringBootHelper.starterSrcDir(baseDir, getStarterArtifactId()), fileName);
 
         deleteFileOnMainArtifact(target);
 
@@ -2204,7 +2201,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
         sb.append(lineToAdd);
 
         String fileName = "META-INF/spring.factories";
-        File target = new File(SpringBootHelper.starterResourceDir(baseDir, project.getArtifactId()), fileName);
+        File target = new File(SpringBootHelper.starterResourceDir(baseDir, getStarterArtifactId()), fileName);
 
         deleteFileOnMainArtifact(target);
 
@@ -2268,12 +2265,20 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo {
         }
     }
 
+    private String getStarterArtifactId() {
+        if ("camel-core-engine".equals(project.getArtifactId())) {
+            return "camel-core";
+        } else {
+            return project.getArtifactId();
+        }
+    }
+
     private void deleteFileOnMainArtifact(File starterFile) {
         if (!DELETE_FILES_ON_MAIN_ARTIFACTS) {
             return;
         }
 
-        String relativePath = SpringBootHelper.starterDir(baseDir, project.getArtifactId()).toPath().relativize(starterFile.toPath()).toString();
+        String relativePath = SpringBootHelper.starterDir(baseDir, getStarterArtifactId()).toPath().relativize(starterFile.toPath()).toString();
         File mainArtifactFile = new File(baseDir, relativePath);
         if (mainArtifactFile.exists()) {
             boolean deleted = mainArtifactFile.delete();


[camel] 04/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 4bcef5892702d129803554b438ecf2bccd5a52cf
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Nov 16 12:59:25 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../camel/blueprint/CamelContextFactoryBean.java   | 23 +++++++++++++++
 .../camel/spring/CamelContextFactoryBean.java      | 31 +++++++++++++++++++-
 .../camel/impl/AbstractModelCamelContext.java      | 21 ++++++++++++++
 .../java/org/apache/camel/impl/DefaultModel.java   | 30 ++++++++++++++++++++
 .../main/java/org/apache/camel/model/Model.java    | 33 ++++++++++++++++++++++
 .../core/xml/AbstractCamelContextFactoryBean.java  | 13 +++++++++
 .../org/apache/camel/main/BaseMainSupport.java     | 30 ++++++++++++++++++--
 7 files changed, 178 insertions(+), 3 deletions(-)

diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index cc3092c..2d40c00 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -55,6 +55,7 @@ import org.apache.camel.model.InterceptSendToEndpointDefinition;
 import org.apache.camel.model.OnCompletionDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
 import org.apache.camel.model.PackageScanDefinition;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
@@ -169,6 +170,10 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     private HystrixConfigurationDefinition defaultHystrixConfiguration;
     @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class)
     private List<HystrixConfigurationDefinition> hystrixConfigurations;
+    @XmlElement(name = "defaultResilience4jConfiguration")
+    private Resilience4jConfigurationDefinition defaultResilience4jConfiguration;
+    @XmlElement(name = "resilience4jConfiguration", type = Resilience4jConfigurationDefinition.class)
+    private List<Resilience4jConfigurationDefinition> resilience4jConfigurations;
     @XmlElement(name = "routeBuilder")
     private List<RouteBuilderDefinition> builderRefs = new ArrayList<>();
     @XmlElement(name = "routeContextRef")
@@ -755,6 +760,24 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     }
 
     @Override
+    public Resilience4jConfigurationDefinition getDefaultResilience4jConfiguration() {
+        return defaultResilience4jConfiguration;
+    }
+
+    public void setDefaultResilience4jConfiguration(Resilience4jConfigurationDefinition defaultResilience4jConfiguration) {
+        this.defaultResilience4jConfiguration = defaultResilience4jConfiguration;
+    }
+
+    @Override
+    public List<Resilience4jConfigurationDefinition> getResilience4jConfigurations() {
+        return resilience4jConfigurations;
+    }
+
+    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> resilience4jConfigurations) {
+        this.resilience4jConfigurations = resilience4jConfigurations;
+    }
+
+    @Override
     public List<RouteBuilderDefinition> getBuilderRefs() {
         return builderRefs;
     }
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index c60d541..cdcf877 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -53,6 +53,7 @@ import org.apache.camel.model.InterceptSendToEndpointDefinition;
 import org.apache.camel.model.OnCompletionDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
 import org.apache.camel.model.PackageScanDefinition;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
@@ -181,6 +182,10 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     private HystrixConfigurationDefinition defaultHystrixConfiguration;
     @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class)
     private List<HystrixConfigurationDefinition> hystrixConfigurations;
+    @XmlElement(name = "defaultResilience4jConfiguration")
+    private Resilience4jConfigurationDefinition defaultResilience4jConfiguration;
+    @XmlElement(name = "resilience4jConfiguration", type = Resilience4jConfigurationDefinition.class)
+    private List<Resilience4jConfigurationDefinition> resilience4jConfigurations;
     @XmlElement(name = "routeBuilder")
     private List<RouteBuilderDefinition> builderRefs = new ArrayList<>();
     @XmlElement(name = "routeContextRef")
@@ -1138,12 +1143,36 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     }
 
     /**
-     * Hystrix EIP configurations
+     * Hystrix Circuit Breaker EIP configurations
      */
     public void setHystrixConfigurations(List<HystrixConfigurationDefinition> hystrixConfigurations) {
         this.hystrixConfigurations = hystrixConfigurations;
     }
 
+    @Override
+    public Resilience4jConfigurationDefinition getDefaultResilience4jConfiguration() {
+        return defaultResilience4jConfiguration;
+    }
+
+    /**
+     * Resilience4j EIP default configuration
+     */
+    public void setDefaultResilience4jConfiguration(Resilience4jConfigurationDefinition defaultResilience4jConfiguration) {
+        this.defaultResilience4jConfiguration = defaultResilience4jConfiguration;
+    }
+
+    @Override
+    public List<Resilience4jConfigurationDefinition> getResilience4jConfigurations() {
+        return resilience4jConfigurations;
+    }
+
+    /**
+     * Resilience4j Circuit Breaker EIP configurations
+     */
+    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> resilience4jConfigurations) {
+        this.resilience4jConfigurations = resilience4jConfigurations;
+    }
+
     /**
      * Configuration of error handlers that triggers on exceptions thrown.
      */
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
index 148f9f0..6a78a7c 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/AbstractModelCamelContext.java
@@ -37,6 +37,7 @@ import org.apache.camel.model.HystrixConfigurationDefinition;
 import org.apache.camel.model.Model;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ProcessorDefinition;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
@@ -186,6 +187,26 @@ public abstract class AbstractModelCamelContext extends AbstractCamelContext imp
     }
 
     @Override
+    public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) {
+        return model.getResilience4jConfiguration(id);
+    }
+
+    @Override
+    public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
+        model.setResilience4jConfiguration(configuration);
+    }
+
+    @Override
+    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) {
+        model.setResilience4jConfigurations(configurations);
+    }
+
+    @Override
+    public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) {
+        model.addResilience4jConfiguration(id, configuration);
+    }
+
+    @Override
     public List<ValidatorDefinition> getValidators() {
         return model.getValidators();
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index 33820bc..f4463d9 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -37,6 +37,7 @@ import org.apache.camel.model.HystrixConfigurationDefinition;
 import org.apache.camel.model.Model;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.ProcessorDefinitionHelper;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteFilters;
@@ -58,6 +59,7 @@ public class DefaultModel implements Model {
     private List<ValidatorDefinition> validators = new ArrayList<>();
     private Map<String, ServiceCallConfigurationDefinition> serviceCallConfigurations = new ConcurrentHashMap<>();
     private Map<String, HystrixConfigurationDefinition> hystrixConfigurations = new ConcurrentHashMap<>();
+    private Map<String, Resilience4jConfigurationDefinition> resilience4jConfigurations = new ConcurrentHashMap<>();
     private Function<RouteDefinition, Boolean> routeFilter;
 
     public DefaultModel(CamelContext camelContext) {
@@ -205,6 +207,34 @@ public class DefaultModel implements Model {
     }
 
     @Override
+    public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) {
+        if (id == null) {
+            id = "";
+        }
+
+        return resilience4jConfigurations.get(id);
+    }
+
+    @Override
+    public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
+        resilience4jConfigurations.put("", configuration);
+    }
+
+    @Override
+    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) {
+        if (configurations != null) {
+            for (Resilience4jConfigurationDefinition configuration : configurations) {
+                resilience4jConfigurations.put(configuration.getId(), configuration);
+            }
+        }
+    }
+
+    @Override
+    public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) {
+        resilience4jConfigurations.put(id, configuration);
+    }
+
+    @Override
     public DataFormatDefinition resolveDataFormatDefinition(String name) {
         // lookup type and create the data format from it
         DataFormatDefinition type = lookup(camelContext, name, DataFormatDefinition.class);
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
index a6aa802..c8bdac7 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Model.java
@@ -201,6 +201,39 @@ public interface Model {
     void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration);
 
     /**
+     * Gets the Resilience4j configuration by the given name. If no name is given the
+     * default configuration is returned, see <tt>setResilience4jConfiguration</tt>
+     *
+     * @param id id of the configuration, or <tt>null</tt> to return the default
+     *            configuration
+     * @return the configuration, or <tt>null</tt> if no configuration has been
+     *         registered
+     */
+    Resilience4jConfigurationDefinition getResilience4jConfiguration(String id);
+
+    /**
+     * Sets the default Resilience4j configuration
+     *
+     * @param configuration the configuration
+     */
+    void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration);
+
+    /**
+     * Sets the Resilience4j configurations
+     *
+     * @param configurations the configuration list
+     */
+    void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations);
+
+    /**
+     * Adds the Resilience4j configuration
+     *
+     * @param id name of the configuration
+     * @param configuration the configuration
+     */
+    void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration);
+
+    /**
      * Gets the validators that can be referenced in the routes.
      *
      * @return the validators available
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 9590014..abb2c29 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -62,6 +62,7 @@ import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.OnCompletionDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
 import org.apache.camel.model.PackageScanDefinition;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
 import org.apache.camel.model.RouteContainer;
@@ -824,6 +825,10 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
 
     public abstract List<HystrixConfigurationDefinition> getHystrixConfigurations();
 
+    public abstract Resilience4jConfigurationDefinition getDefaultResilience4jConfiguration();
+
+    public abstract List<Resilience4jConfigurationDefinition> getResilience4jConfigurations();
+
     // Implementation methods
     // -------------------------------------------------------------------------
 
@@ -928,6 +933,14 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
                 context.addHystrixConfiguration(bean.getId(), bean);
             }
         }
+        if (getDefaultResilience4jConfiguration() != null) {
+            context.setResilience4jConfiguration(getDefaultResilience4jConfiguration());
+        }
+        if (getResilience4jConfigurations() != null) {
+            for (Resilience4jConfigurationDefinition bean : getResilience4jConfigurations()) {
+                context.addResilience4jConfiguration(bean.getId(), bean);
+            }
+        }
     }
 
     protected void initThreadPoolProfiles(T context) throws Exception {
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 dd64a90..542ed8c 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
@@ -43,6 +43,7 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.model.HystrixConfigurationDefinition;
 import org.apache.camel.model.Model;
 import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.DataFormat;
@@ -658,6 +659,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
 
         Map<String, Object> contextProperties = new LinkedHashMap<>();
         Map<String, Object> hystrixProperties = new LinkedHashMap<>();
+        Map<String, Object> resilience4jProperties = new LinkedHashMap<>();
         Map<String, Object> restProperties = new LinkedHashMap<>();
         for (String key : prop.stringPropertyNames()) {
             if (key.startsWith("camel.context.")) {
@@ -672,6 +674,12 @@ public abstract class BaseMainSupport extends ServiceSupport {
                 String option = key.substring(14);
                 validateOptionAndValue(key, option, value);
                 hystrixProperties.put(optionKey(option), value);
+            } else if (key.startsWith("camel.resilience4j.")) {
+                // grab the value
+                String value = prop.getProperty(key);
+                String option = key.substring(19);
+                validateOptionAndValue(key, option, value);
+                resilience4jProperties.put(optionKey(option), value);
             } else if (key.startsWith("camel.rest.")) {
                 // grab the value
                 String value = prop.getProperty(key);
@@ -686,14 +694,25 @@ public abstract class BaseMainSupport extends ServiceSupport {
                     mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
         }
         if (!hystrixProperties.isEmpty()) {
-            LOG.debug("Auto-configuring Hystrix EIP from loaded properties: {}", hystrixProperties.size());
+            LOG.debug("Auto-configuring Hystrix Circuit Breaker EIP from loaded properties: {}", hystrixProperties.size());
             ModelCamelContext model = camelContext.adapt(ModelCamelContext.class);
             HystrixConfigurationDefinition hystrix = model.getHystrixConfiguration(null);
             if (hystrix == null) {
                 hystrix = new HystrixConfigurationDefinition();
                 model.setHystrixConfiguration(hystrix);
             }
-            setPropertiesOnTarget(camelContext, hystrix, hystrixProperties, null, "camel.hsytrix.",
+            setPropertiesOnTarget(camelContext, hystrix, hystrixProperties, null, "camel.hystrix.",
+                    mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
+        }
+        if (!resilience4jProperties.isEmpty()) {
+            LOG.debug("Auto-configuring Resilience4j Circuit Breaker EIP from loaded properties: {}", resilience4jProperties.size());
+            ModelCamelContext model = camelContext.adapt(ModelCamelContext.class);
+            Resilience4jConfigurationDefinition resilience4j = model.getResilience4jConfiguration(null);
+            if (resilience4j == null) {
+                resilience4j = new Resilience4jConfigurationDefinition();
+                model.setResilience4jConfiguration(resilience4j);
+            }
+            setPropertiesOnTarget(camelContext, resilience4j, hystrixProperties, null, "camel.resilience4j.",
                     mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
         }
         if (!restProperties.isEmpty()) {
@@ -721,6 +740,13 @@ public abstract class BaseMainSupport extends ServiceSupport {
                 LOG.warn("Property not auto-configured: camel.hystrix.{}={} on bean: {}", k, v, hystrix);
             });
         }
+        if (!resilience4jProperties.isEmpty()) {
+            ModelCamelContext model = camelContext.adapt(ModelCamelContext.class);
+            Resilience4jConfigurationDefinition resilience4j = model.getResilience4jConfiguration(null);
+            resilience4jProperties.forEach((k, v) -> {
+                LOG.warn("Property not auto-configured: camel.resilience4j.{}={} on bean: {}", k, v, resilience4j);
+            });
+        }
         if (!restProperties.isEmpty()) {
             ModelCamelContext model = camelContext.adapt(ModelCamelContext.class);
             RestConfiguration rest = model.getRestConfiguration();


[camel] 20/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit da9c01a0510e03a606215e6beedd40e10fbb787b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 08:10:13 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceConstants.java          | 23 +++++
 .../src/main/resources/application.properties      | 11 +--
 .../springboot/ResilienceAutoConfiguration.java    | 99 ++++++++++++++++++++++
 .../src/main/resources/META-INF/spring.factories   | 15 +---
 4 files changed, 130 insertions(+), 18 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceConstants.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceConstants.java
new file mode 100644
index 0000000..b8443e5
--- /dev/null
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceConstants.java
@@ -0,0 +1,23 @@
+/*
+ * 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.component.resilience4j;
+
+public interface ResilienceConstants {
+
+    String DEFAULT_RESILIENCE_CONFIGURATION_ID = "resilience4j-configuration";
+
+}
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/application.properties b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
index c3a7ed9..eafb09b 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/application.properties
+++ b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
@@ -20,11 +20,12 @@ server.port=8080
 # configure resilience4j
 # when we have more than 5 requests per 10 seconds that 50%+ fails
 # then open circuit and call fallback immediately
-// TODO: configure these
-camel.resilience.sliding-window-type=
-camel.hystrix.circuit-breaker-request-volume-threshold=5
-camel.hystrix.circuit-breaker-error-threshold-percentage=50
-camel.hystrix.metrics-rolling-percentile-window-in-milliseconds=10000
+camel.resilience4j.minimum-number-of-calls=5
+camel.resilience4j.sliding-window-size=10
+camel.resilience4j.sliding-window-type=TIME_BASED
+camel.resilience4j.failure-rate-threshold=50
+# stay in open for 10s before switching back to half-open
+camel.resilience4j.wait-duration-in-open-state=10
 
 # resilience4j logging
 #logging.level.org.apache.camel.component.resilience=DEBUG
diff --git a/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/java/org/apache/camel/component/resilience/springboot/ResilienceAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/java/org/apache/camel/component/resilience/springboot/ResilienceAutoConfiguration.java
new file mode 100644
index 0000000..c9ecdee
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/java/org/apache/camel/component/resilience/springboot/ResilienceAutoConfiguration.java
@@ -0,0 +1,99 @@
+/*
+ * 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.component.resilience.springboot;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.resilience4j.ResilienceConstants;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.springboot.Resilience4jConfigurationDefinitionCommon;
+import org.apache.camel.model.springboot.Resilience4jConfigurationDefinitionProperties;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.support.IntrospectionSupport;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Resilience auto configuration.
+ */
+@Configuration
+@ConditionalOnProperty(name = "camel.resilience4j.enabled", matchIfMissing = true)
+@ConditionalOnBean(value = CamelAutoConfiguration.class)
+@AutoConfigureAfter(value = CamelAutoConfiguration.class)
+@EnableConfigurationProperties(Resilience4jConfigurationDefinitionProperties.class)
+public class ResilienceAutoConfiguration {
+    @Autowired
+    private ConfigurableBeanFactory beanFactory;
+    @Autowired
+    private CamelContext camelContext;
+    @Autowired
+    private Resilience4jConfigurationDefinitionProperties config;
+
+    @Bean(name = ResilienceConstants.DEFAULT_RESILIENCE_CONFIGURATION_ID)
+    @ConditionalOnClass(CamelContext.class)
+    @ConditionalOnMissingBean(name = ResilienceConstants.DEFAULT_RESILIENCE_CONFIGURATION_ID)
+    public Resilience4jConfigurationDefinition defaultResilienceConfigurationDefinition() throws Exception {
+        Map<String, Object> properties = new HashMap<>();
+
+        IntrospectionSupport.getProperties(config, properties, null, false);
+        Resilience4jConfigurationDefinition definition = new Resilience4jConfigurationDefinition();
+        IntrospectionSupport.setProperties(camelContext, camelContext.getTypeConverter(), definition, properties);
+
+        return definition;
+    }
+
+    @PostConstruct
+    public void postConstruct() {
+        if (beanFactory == null) {
+            return;
+        }
+
+        Map<String, Object> properties = new HashMap<>();
+
+        for (Map.Entry<String, Resilience4jConfigurationDefinitionCommon> entry : config.getConfigurations().entrySet()) {
+
+            // clear the properties map for reuse
+            properties.clear();
+
+            // extract properties
+            IntrospectionSupport.getProperties(entry.getValue(), properties, null, false);
+
+            try {
+                Resilience4jConfigurationDefinition definition = new Resilience4jConfigurationDefinition();
+                IntrospectionSupport.setProperties(camelContext, camelContext.getTypeConverter(), definition, properties);
+
+                // Registry the definition
+                beanFactory.registerSingleton(entry.getKey(), definition);
+
+            } catch (Exception e) {
+                throw new BeanCreationException(entry.getKey(), e);
+            }
+        }
+    }
+}
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/application.properties b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.factories
similarity index 66%
copy from examples/camel-example-resilience4j/client/src/main/resources/application.properties
copy to platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.factories
index c3a7ed9..93d1a24 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/application.properties
+++ b/platforms/spring-boot/components-starter/camel-resilience4j-starter/src/main/resources/META-INF/spring.factories
@@ -14,17 +14,6 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.camel.component.resilience.springboot.ResilienceAutoConfiguration
 
-server.port=8080
-
-# configure resilience4j
-# when we have more than 5 requests per 10 seconds that 50%+ fails
-# then open circuit and call fallback immediately
-// TODO: configure these
-camel.resilience.sliding-window-type=
-camel.hystrix.circuit-breaker-request-volume-threshold=5
-camel.hystrix.circuit-breaker-error-threshold-percentage=50
-camel.hystrix.metrics-rolling-percentile-window-in-milliseconds=10000
-
-# resilience4j logging
-#logging.level.org.apache.camel.component.resilience=DEBUG


[camel] 10/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit dc6bf8a48344c803975c54d45aef180e819e4dc3
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 11:15:33 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../src/main/docs/resilience4j.adoc                |  12 --
 .../resilience4j/ResilienceProcessor.java          | 102 +++++++----
 .../component/resilience4j/ResilienceReifier.java  |  20 ++-
 ...TimeoutTest.java => ResilienceTimeoutTest.java} |  20 +--
 ...java => ResilienceTimeoutWithFallbackTest.java} |  20 +--
 .../model/Resilience4jConfigurationCommon.java     |  43 +++++
 .../model/Resilience4jConfigurationDefinition.java |  28 +++
 .../main/Resilience4jConfigurationProperties.java  |  67 ++++++++
 .../camel-main-configuration-metadata.json         | 191 ++++++++++++---------
 9 files changed, 345 insertions(+), 158 deletions(-)

diff --git a/components/camel-resilience4j/src/main/docs/resilience4j.adoc b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
index 0bf1b56..deb5122 100644
--- a/components/camel-resilience4j/src/main/docs/resilience4j.adoc
+++ b/components/camel-resilience4j/src/main/docs/resilience4j.adoc
@@ -34,16 +34,4 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 </dependency>
 ----
 
-
-The component supports 3 options, which are listed below.
-
-
-
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *camel.component.hystrix.mapping.enabled* | Enables the automatic mapping of the hystrics metric servlet into the Spring web context. | true | Boolean
-| *camel.component.hystrix.mapping.path* | Endpoint for hystrix metrics servlet. | /hystrix.stream | String
-| *camel.component.hystrix.mapping.servlet-name* | Name of the Hystrix metrics servlet. | HystrixEventStreamServlet | String
-|===
 // spring-boot-auto-configure options: END
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index cbc57ec..50acd37 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -18,6 +18,9 @@ package org.apache.camel.component.resilience4j;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeoutException;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
@@ -25,6 +28,8 @@ import io.github.resilience4j.bulkhead.Bulkhead;
 import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
+import io.github.resilience4j.timelimiter.TimeLimiter;
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
 import io.vavr.control.Try;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
@@ -50,13 +55,15 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
     private String id;
     private CircuitBreakerConfig circuitBreakerConfig;
     private BulkheadConfig bulkheadConfig;
+    private TimeLimiterConfig timeLimiterConfig;
     private final Processor processor;
     private final Processor fallback;
 
-    public ResilienceProcessor(CircuitBreakerConfig circuitBreakerConfig, BulkheadConfig bulkheadConfig,
+    public ResilienceProcessor(CircuitBreakerConfig circuitBreakerConfig, BulkheadConfig bulkheadConfig, TimeLimiterConfig timeLimiterConfig,
                                Processor processor, Processor fallback) {
         this.circuitBreakerConfig = circuitBreakerConfig;
         this.bulkheadConfig = bulkheadConfig;
+        this.timeLimiterConfig = timeLimiterConfig;
         this.processor = processor;
         this.fallback = fallback;
     }
@@ -149,26 +156,31 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         // run this as if we run inside try .. catch so there is no regular Camel error handler
         exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true);
 
-//        Supplier<CompletableFuture<String>> futureSupplier = () -> CompletableFuture.supplyAsync(() -> "Hello");
-//        Callable<String> callable = TimeLimiter.decorateFutureSupplier(TimeLimiter.of(Duration.ofMillis(500)), futureSupplier);
-//        String result = CircuitBreaker.decorateCheckedSupplier(cb, callable::call).apply();
-
-//                TimeLimiter time = TimeLimiter.of(Duration.ofSeconds(1));
-//        Supplier<Future<Exchange>> task2 = time.decorateFutureSupplier(() -> {
-//            task.get();
-//            Future
-//        });
-
         CircuitBreaker cb = CircuitBreaker.of(id, circuitBreakerConfig);
 
-        Supplier<Exchange> task = CircuitBreaker.decorateSupplier(cb, new CircuitBreakerTask(processor, exchange));
+        Callable<Exchange> task = CircuitBreaker.decorateCallable(cb, new CircuitBreakerTask(processor, exchange));
         Function<Throwable, Exchange> fallbackTask = new CircuitBreakerFallbackTask(fallback, exchange);
         if (bulkheadConfig != null) {
             Bulkhead bh = Bulkhead.of(id, bulkheadConfig);
-            task = Bulkhead.decorateSupplier(bh, task);
+            task = Bulkhead.decorateCallable(bh, task);
+        }
+        // timeout handling is more complex with thread-pools
+        // TODO: Allow to plugin custom thread-pool instead of JDKs
+        if (timeLimiterConfig != null) {
+            final Callable<Exchange> future = task;
+            Supplier<CompletableFuture<Exchange>> futureSupplier = () -> CompletableFuture.supplyAsync(() -> {
+                try {
+                    return future.call();
+                } catch (Exception e) {
+                    exchange.setException(e);
+                }
+                return exchange;
+            });
+            TimeLimiter tl = TimeLimiter.of(id, timeLimiterConfig);
+            task = TimeLimiter.decorateFutureSupplier(tl, futureSupplier);
         }
 
-        Try.ofSupplier(task)
+        Try.ofCallable(task)
                 .recover(fallbackTask)
                 .andFinally(() -> callback.done(false)).get();
 
@@ -185,7 +197,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         // noop
     }
 
-    private static class CircuitBreakerTask implements Supplier<Exchange> {
+    private static class CircuitBreakerTask implements Callable<Exchange> {
 
         private final Processor processor;
         private final Exchange exchange;
@@ -196,7 +208,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         }
 
         @Override
-        public Exchange get() {
+        public Exchange call() throws Exception {
             try {
                 LOG.debug("Running processor: {} with exchange: {}", processor, exchange);
                 // prepare a copy of exchange so downstream processors don't cause side-effects if they mutate the exchange
@@ -235,31 +247,45 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 
         @Override
         public Exchange apply(Throwable throwable) {
-            if (processor != null) {
-                // store the last to endpoint as the failure endpoint
-                if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
-                    exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
-                }
-                // give the rest of the pipeline another chance
-                exchange.setProperty(Exchange.EXCEPTION_HANDLED, true);
-                exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException());
-                exchange.removeProperty(Exchange.ROUTE_STOP);
-                exchange.setException(null);
-                // and we should not be regarded as exhausted as we are in a try .. catch block
-                exchange.removeProperty(Exchange.REDELIVERY_EXHAUSTED);
-                // run the fallback processor
-                try {
-                    LOG.debug("Running fallback: {} with exchange: {}", processor, exchange);
-                    // process the fallback until its fully done
-                    processor.process(exchange);
-                    LOG.debug("Running fallback: {} with exchange: {} done", processor, exchange);
-                } catch (Exception e) {
-                    exchange.setException(e);
+            if (processor == null) {
+                if (throwable instanceof TimeoutException) {
+                    // the circuit breaker triggered a timeout (and there is no fallback) so lets mark the exchange as failed
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_TIMED_OUT, true);
+                    exchange.setException(throwable);
+                    return exchange;
+                } else {
+                    // throw exception so resilient4j know it was a failure
+                    throw RuntimeExchangeException.wrapRuntimeException(throwable);
                 }
+            }
+
+            // fallback route is handling the exception
 
-                exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
-                exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+            // store the last to endpoint as the failure endpoint
+            if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
+                exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
             }
+            // give the rest of the pipeline another chance
+            exchange.setProperty(Exchange.EXCEPTION_HANDLED, true);
+            exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException());
+            exchange.removeProperty(Exchange.ROUTE_STOP);
+            exchange.setException(null);
+            // and we should not be regarded as exhausted as we are in a try .. catch block
+            exchange.removeProperty(Exchange.REDELIVERY_EXHAUSTED);
+            // run the fallback processor
+            try {
+                LOG.debug("Running fallback: {} with exchange: {}", processor, exchange);
+                // process the fallback until its fully done
+                processor.process(exchange);
+                LOG.debug("Running fallback: {} with exchange: {} done", processor, exchange);
+            } catch (Exception e) {
+                exchange.setException(e);
+            }
+
+            exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+            exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
 
             return exchange;
         }
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index a9b3d00..95da2a4 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -24,6 +24,7 @@ import java.util.Optional;
 import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 
+import io.github.resilience4j.timelimiter.TimeLimiterConfig;
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
@@ -44,7 +45,6 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
 
     // TODO: metrics with state of CB
     // TODO: expose metrics as JMX on processor
-    // TODO: Timeout
     // TODO: thread pool bulkhead
     // TODO: spring-boot allow to configure via resilience4j-spring-boot
     // TODO: example
@@ -69,8 +69,9 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         final Resilience4jConfigurationCommon config = buildResilience4jConfiguration(routeContext.getCamelContext());
         CircuitBreakerConfig cbConfig = configureCircuitBreaker(config);
         BulkheadConfig bhConfig = configureBulkHead(config);
+        TimeLimiterConfig tlConfig = configureTimeLimiter(config);
 
-        return new ResilienceProcessor(cbConfig, bhConfig, processor, fallback);
+        return new ResilienceProcessor(cbConfig, bhConfig, tlConfig, processor, fallback);
     }
 
     private CircuitBreakerConfig configureCircuitBreaker(Resilience4jConfigurationCommon config) {
@@ -123,6 +124,21 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         return builder.build();
     }
 
+    private TimeLimiterConfig configureTimeLimiter(Resilience4jConfigurationCommon config) {
+        if (config.getTimeoutEnabled() == null || !config.getTimeoutEnabled()) {
+            return null;
+        }
+
+        TimeLimiterConfig.Builder builder = TimeLimiterConfig.custom();
+        if (config.getTimeoutDuration() != null) {
+            builder.timeoutDuration(Duration.ofMillis(config.getTimeoutDuration()));
+        }
+        if (config.getTimeoutCancelRunningFuture() != null) {
+            builder.cancelRunningFuture(config.getTimeoutCancelRunningFuture());
+        }
+        return builder.build();
+    }
+
     // *******************************
     // Helpers
     // *******************************
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutTest.java
similarity index 86%
rename from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java
rename to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutTest.java
index 63abdba..9545b1f 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutTest.java
@@ -21,14 +21,12 @@ import java.util.concurrent.TimeoutException;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
- * Hystrix using timeout with Java DSL
+ * Resilience using timeout with Java DSL
  */
-@Ignore
-public class HystrixTimeoutTest extends CamelTestSupport {
+public class ResilienceTimeoutTest extends CamelTestSupport {
 
     @Test
     public void testFast() throws Exception {
@@ -45,7 +43,7 @@ public class HystrixTimeoutTest extends CamelTestSupport {
             fail("Should fail due to timeout");
         } catch (Exception e) {
             // expected a timeout
-            assertIsInstanceOf(TimeoutException.class, e.getCause().getCause());
+            assertIsInstanceOf(TimeoutException.class, e.getCause());
         }
     }
 
@@ -59,7 +57,7 @@ public class HystrixTimeoutTest extends CamelTestSupport {
                 fail("Should fail due to timeout");
             } catch (Exception e) {
                 // expected a timeout
-                assertIsInstanceOf(TimeoutException.class, e.getCause().getCause());
+                assertIsInstanceOf(TimeoutException.class, e.getCause());
             }
         }
     }
@@ -71,13 +69,13 @@ public class HystrixTimeoutTest extends CamelTestSupport {
             public void configure() throws Exception {
                 from("direct:start")
                     .circuitBreaker()
-                        // use 2 second timeout
-                        .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
-                        .log("Hystrix processing start: ${threadName}")
+                        // enable and use 2 second timeout
+                        .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end()
+                        .log("Resilience processing start: ${threadName}")
                         .toD("direct:${body}")
-                        .log("Hystrix processing end: ${threadName}")
+                        .log("Resilience processing end: ${threadName}")
                     .end()
-                    .log("After Hystrix ${body}");
+                    .log("After Resilience ${body}");
 
                 from("direct:fast")
                     // this is a fast route and takes 1 second to respond
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackTest.java
similarity index 82%
rename from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.java
rename to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackTest.java
index 9a8bb67..ef6f5bf 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixTimeoutWithFallbackTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutWithFallbackTest.java
@@ -19,14 +19,12 @@ package org.apache.camel.component.resilience4j;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
- * Hystrix using timeout and fallback with Java DSL
+ * Resilience using timeout and fallback with Java DSL
  */
-@Ignore
-public class HystrixTimeoutWithFallbackTest extends CamelTestSupport {
+public class ResilienceTimeoutWithFallbackTest extends CamelTestSupport {
 
     @Test
     public void testFast() throws Exception {
@@ -49,18 +47,18 @@ public class HystrixTimeoutWithFallbackTest extends CamelTestSupport {
             public void configure() throws Exception {
                 from("direct:start")
                     .circuitBreaker()
-                    // use 2 second timeout
-                    .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
-                        .log("Hystrix processing start: ${threadName}")
+                    // enable and use 2 second timeout
+                    .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end()
+                        .log("Resilience processing start: ${threadName}")
                         .toD("direct:${body}")
-                        .log("Hystrix processing end: ${threadName}")
+                        .log("Resilience processing end: ${threadName}")
                     .onFallback()
                         // use fallback if there was an exception or timeout
-                        .log("Hystrix fallback start: ${threadName}")
+                        .log("Resilience fallback start: ${threadName}")
                         .transform().constant("Fallback response")
-                        .log("Hystrix fallback end: ${threadName}")
+                        .log("Resilience fallback end: ${threadName}")
                     .end()
-                    .log("After Hystrix ${body}")
+                    .log("After Resilience ${body}")
                     .transform(simple("A CHANGE"))
                     .transform(simple("LAST CHANGE"))
                     .log("End ${body}");
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
index 771211d..208f8b0 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -64,6 +64,12 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
     private Integer bulkheadMaxConcurrentCalls;
     @Metadata(label = "bulkhead", defaultValue = "0")
     private Integer bulkheadMaxWaitDuration;
+    @Metadata(label = "timeout", defaultValue = "false")
+    private Boolean timeoutEnabled;
+    @Metadata(label = "timeout", defaultValue = "1000")
+    private Integer timeoutDuration;
+    @Metadata(label = "timeout", defaultValue = "true")
+    private Boolean timeoutCancelRunningFuture;
 
     // Getter/Setter
     // -------------------------------------------------------------------------
@@ -229,6 +235,7 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
 
     /**
      * Whether bulkhead is enabled or not on the circuit breaker.
+     * Default is false.
      */
     public void setBulkheadEnabled(Boolean bulkheadEnabled) {
         this.bulkheadEnabled = bulkheadEnabled;
@@ -259,4 +266,40 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
     public void setBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) {
         this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
     }
+
+    public Boolean getTimeoutEnabled() {
+        return timeoutEnabled;
+    }
+
+    /**
+     * Whether timeout is enabled or not on the circuit breaker.
+     * Default is false.
+     */
+    public void setTimeoutEnabled(Boolean timeoutEnabled) {
+        this.timeoutEnabled = timeoutEnabled;
+    }
+
+    public Integer getTimeoutDuration() {
+        return timeoutDuration;
+    }
+
+    /**
+     * Configures the thread execution timeout.
+     * Default value is 1 second.
+     */
+    public void setTimeoutDuration(Integer timeoutDuration) {
+        this.timeoutDuration = timeoutDuration;
+    }
+
+    public Boolean getTimeoutCancelRunningFuture() {
+        return timeoutCancelRunningFuture;
+    }
+
+    /**
+     * Configures whether cancel is called on the running future.
+     * Defaults to true.
+     */
+    public void setTimeoutCancelRunningFuture(Boolean timeoutCancelRunningFuture) {
+        this.timeoutCancelRunningFuture = timeoutCancelRunningFuture;
+    }
 }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
index 015feeb..76eadb0 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -168,6 +168,7 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
 
     /**
      * Whether bulkhead is enabled or not on the circuit breaker.
+     * Default is false.
      */
     public Resilience4jConfigurationDefinition bulkheadEnabled(Boolean bulkheadEnabled) {
         setBulkheadEnabled(bulkheadEnabled);
@@ -195,6 +196,33 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
     }
 
     /**
+     * Whether timeout is enabled or not on the circuit breaker.
+     * Default is false.
+     */
+    public Resilience4jConfigurationDefinition timeoutEnabled(Boolean timeoutEnabled) {
+        setTimeoutEnabled(timeoutEnabled);
+        return this;
+    }
+
+    /**
+     * Configures the thread execution timeout (millis).
+     * Default value is 1000 millis (1 second).
+     */
+    public Resilience4jConfigurationDefinition timeoutDuration(Integer timeoutDuration) {
+        setTimeoutDuration(timeoutDuration);
+        return this;
+    }
+
+    /**
+     * Configures whether cancel is called on the running future.
+     * Defaults to true.
+     */
+    public Resilience4jConfigurationDefinition timeoutCancelRunningFuture(Boolean timeoutCancelRunningFuture) {
+        setTimeoutCancelRunningFuture(timeoutCancelRunningFuture);
+        return this;
+    }
+
+    /**
      * End of configuration.
      */
     public CircuitBreakerDefinition end() {
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
index db9c7b8..81c1ca9 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
@@ -37,6 +37,9 @@ public class Resilience4jConfigurationProperties {
     private Boolean bulkheadEnabled;
     private Integer bulkheadMaxConcurrentCalls;
     private Integer bulkheadMaxWaitDuration;
+    private Boolean timeoutEnabled;
+    private Integer timeoutDuration;
+    private Boolean timeoutCancelRunningFuture;
 
     public Resilience4jConfigurationProperties(MainConfigurationProperties parent) {
         this.parent = parent;
@@ -241,6 +244,42 @@ public class Resilience4jConfigurationProperties {
         this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
     }
 
+    public Boolean getTimeoutEnabled() {
+        return timeoutEnabled;
+    }
+
+    /**
+     * Whether timeout is enabled or not on the circuit breaker.
+     * Default is false.
+     */
+    public void setTimeoutEnabled(Boolean timeoutEnabled) {
+        this.timeoutEnabled = timeoutEnabled;
+    }
+
+    public Integer getTimeoutDuration() {
+        return timeoutDuration;
+    }
+
+    /**
+     * Configures the thread execution timeout (millis).
+     * Default value is 1000 millis (1 second).
+     */
+    public void setTimeoutDuration(Integer timeoutDuration) {
+        this.timeoutDuration = timeoutDuration;
+    }
+
+    public Boolean getTimeoutCancelRunningFuture() {
+        return timeoutCancelRunningFuture;
+    }
+
+    /**
+     * Configures whether cancel is called on the running future.
+     * Defaults to true.
+     */
+    public void setTimeoutCancelRunningFuture(Boolean timeoutCancelRunningFuture) {
+        this.timeoutCancelRunningFuture = timeoutCancelRunningFuture;
+    }
+
     /**
      * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
      * to lookup and use from the registry.
@@ -387,4 +426,32 @@ public class Resilience4jConfigurationProperties {
         this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
         return this;
     }
+
+    /**
+     * Whether timeout is enabled or not on the circuit breaker.
+     * Default is false.
+     */
+    public Resilience4jConfigurationProperties withTimeoutEnabled(Boolean timeoutEnabled) {
+        this.timeoutEnabled = timeoutEnabled;
+        return this;
+    }
+
+    /**
+     * Configures the thread execution timeout (millis).
+     * Default value is 1000 millis (1 second).
+     */
+    public Resilience4jConfigurationProperties withTimeoutDuration(Integer timeoutDuration) {
+        this.timeoutDuration = timeoutDuration;
+        return this;
+    }
+
+    /**
+     * Configures whether cancel is called on the running future.
+     * Defaults to true.
+     */
+    public Resilience4jConfigurationProperties withTimeoutCancelRunningFuture(Boolean timeoutCancelRunningFuture) {
+        this.timeoutCancelRunningFuture = timeoutCancelRunningFuture;
+        return this;
+    }
+
 }
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 0713982..6aac40d 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -11,6 +11,11 @@
 			"sourceType":"org.apache.camel.main.HystrixConfigurationProperties"
 		},
 		{
+			"name":"camel.resilience4j",
+			"description":"camel-resilience4j configurations.",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties"
+		},
+		{
 			"name":"camel.rest",
 			"description":"camel-rest configurations.",
 			"sourceType":"org.apache.camel.spi.RestConfiguration"
@@ -52,12 +57,6 @@
 			"defaultValue":"true"
 		},
 		{
-			"name":"camel.main.automatic-transition-from-open-to-half-open-enabled",
-			"type":"java.lang.Boolean",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed."
-		},
-		{
 			"name":"camel.main.auto-startup",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -109,30 +108,6 @@
 			"description":"Sets the logging level used by bean introspection, logging activity of its usage. The default is TRACE."
 		},
 		{
-			"name":"camel.main.bulkhead-enabled",
-			"type":"java.lang.Boolean",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Whether bulkhead is enabled or not on the circuit breaker."
-		},
-		{
-			"name":"camel.main.bulkhead-max-concurrent-calls",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the max amount of concurrent calls the bulkhead will support."
-		},
-		{
-			"name":"camel.main.bulkhead-max-wait-duration",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a ne [...]
-		},
-		{
-			"name":"camel.main.config-ref",
-			"type":"java.lang.String",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry."
-		},
-		{
 			"name":"camel.main.consumer-template-cache-size",
 			"type":"int",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -188,12 +163,6 @@
 			"description":"Sets whether endpoint runtime statistics is enabled (gathers runtime usage of each incoming and outgoing endpoints). The default value is false."
 		},
 		{
-			"name":"camel.main.failure-rate-threshold",
-			"type":"java.lang.Float",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the failure rate threshold in percentage. If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage."
-		},
-		{
 			"name":"camel.main.file-configurations",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -284,12 +253,6 @@
 			"defaultValue":"true"
 		},
 		{
-			"name":"camel.main.minimum-number-of-calls",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate. For example, if minimumNumberOfCalls is 10, then at least 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100"
-		},
-		{
 			"name":"camel.main.name",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -302,12 +265,6 @@
 			"description":"Sets package names for scanning for org.apache.camel.builder.RouteBuilder classes as candidates to be included. If you are using Spring Boot then its instead recommended to use Spring Boots component scanning and annotate your route builder classes with Component. In other words only use this for Camel Main in standalone mode."
 		},
 		{
-			"name":"camel.main.permitted-number-of-calls-in-half-open-state",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10."
-		},
-		{
 			"name":"camel.main.producer-template-cache-size",
 			"type":"int",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -368,30 +325,6 @@
 			"defaultValue":"300"
 		},
 		{
-			"name":"camel.main.sliding-window-size",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. slidingWindowSize configures the size of the sliding window. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize m [...]
-		},
-		{
-			"name":"camel.main.sliding-window-type",
-			"type":"java.lang.String",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED."
-		},
-		{
-			"name":"camel.main.slow-call-duration-threshold",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds."
-		},
-		{
-			"name":"camel.main.slow-call-rate-threshold",
-			"type":"java.lang.Float",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold."
-		},
-		{
 			"name":"camel.main.stream-caching-any-spool-rules",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -489,18 +422,6 @@
 			"description":"To turn on MDC logging"
 		},
 		{
-			"name":"camel.main.wait-duration-in-open-state",
-			"type":"java.lang.Integer",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds."
-		},
-		{
-			"name":"camel.main.writable-stack-trace-enabled",
-			"type":"java.lang.Boolean",
-			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls)."
-		},
-		{
 			"name":"camel.main.xml-rests",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -701,6 +622,108 @@
 			"description":"Duration of statistical rolling window in milliseconds. This is passed into HystrixRollingNumber inside each HystrixThreadPoolMetrics instance."
 		},
 		{
+			"name":"camel.resilience4j.automatic-transition-from-open-to-half-open-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed."
+		},
+		{
+			"name":"camel.resilience4j.bulkhead-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Whether bulkhead is enabled or not on the circuit breaker."
+		},
+		{
+			"name":"camel.resilience4j.bulkhead-max-concurrent-calls",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the max amount of concurrent calls the bulkhead will support."
+		},
+		{
+			"name":"camel.resilience4j.bulkhead-max-wait-duration",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a ne [...]
+		},
+		{
+			"name":"camel.resilience4j.config-ref",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry."
+		},
+		{
+			"name":"camel.resilience4j.failure-rate-threshold",
+			"type":"java.lang.Float",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the failure rate threshold in percentage. If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage."
+		},
+		{
+			"name":"camel.resilience4j.minimum-number-of-calls",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate. For example, if minimumNumberOfCalls is 10, then at least 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100"
+		},
+		{
+			"name":"camel.resilience4j.permitted-number-of-calls-in-half-open-state",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10."
+		},
+		{
+			"name":"camel.resilience4j.sliding-window-size",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. slidingWindowSize configures the size of the sliding window. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize m [...]
+		},
+		{
+			"name":"camel.resilience4j.sliding-window-type",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED."
+		},
+		{
+			"name":"camel.resilience4j.slow-call-duration-threshold",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds."
+		},
+		{
+			"name":"camel.resilience4j.slow-call-rate-threshold",
+			"type":"java.lang.Float",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold."
+		},
+		{
+			"name":"camel.resilience4j.timeout-cancel-running-future",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures whether cancel is called on the running future. Defaults to true."
+		},
+		{
+			"name":"camel.resilience4j.timeout-duration",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the thread execution timeout. Default value is 1 second."
+		},
+		{
+			"name":"camel.resilience4j.timeout-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Whether timeout is enabled or not on the circuit breaker. Default is false."
+		},
+		{
+			"name":"camel.resilience4j.wait-duration-in-open-state",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds."
+		},
+		{
+			"name":"camel.resilience4j.writable-stack-trace-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls)."
+		},
+		{
 			"name":"camel.rest.api-component",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.spi.RestConfiguration",


[camel] 06/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit d8cec60d7ba8ff777917910d43c46126336cb6f2
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 08:50:22 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 bom/camel-bom/pom.xml                              | 10 +++
 .../resilience4j/ResilienceProcessor.java          | 78 +++++++++++++++++---
 .../component/resilience4j/ResilienceReifier.java  | 31 ++++++--
 .../resilience4j/ResilienceManagementTest.java     | 83 ++++++++++++++++++++++
 ...va => ResilienceRouteBulkheadFallbackTest.java} | 10 ++-
 ...est.java => ResilienceRouteBulkheadOkTest.java} | 23 +++---
 ... => ResilienceRouteFallbackViaNetworkTest.java} | 26 ++++---
 .../model/Resilience4jConfigurationCommon.java     | 78 +++++++++++++++-----
 .../model/Resilience4jConfigurationDefinition.java | 37 ++++++++--
 docs/user-manual/modules/ROOT/nav.adoc             |  2 +
 .../modules/ROOT/pages/hystrix-eip.adoc            | 14 ++--
 .../{hystrix-eip.adoc => resilience4j-eip.adoc}    | 54 +++++++-------
 .../ROOT/pages/resilience4jConfiguration-eip.adoc  |  7 ++
 .../camel-spring-boot-dependencies/pom.xml         | 10 +++
 14 files changed, 361 insertions(+), 102 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index a1a49bc..9a34d63 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -2365,6 +2365,16 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-rest</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 91fa38c..cbc57ec 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -21,6 +21,8 @@ import java.util.List;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import io.github.resilience4j.bulkhead.Bulkhead;
+import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 import io.vavr.control.Try;
@@ -29,6 +31,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeExchangeException;
+import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
@@ -45,16 +48,17 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
     private static final Logger LOG = LoggerFactory.getLogger(ResilienceProcessor.class);
 
     private String id;
-    private CircuitBreakerConfig config;
+    private CircuitBreakerConfig circuitBreakerConfig;
+    private BulkheadConfig bulkheadConfig;
     private final Processor processor;
     private final Processor fallback;
-    private final boolean fallbackViaNetwork;
 
-    public ResilienceProcessor(CircuitBreakerConfig config, Processor processor, Processor fallback, boolean fallbackViaNetwork) {
-        this.config = config;
+    public ResilienceProcessor(CircuitBreakerConfig circuitBreakerConfig, BulkheadConfig bulkheadConfig,
+                               Processor processor, Processor fallback) {
+        this.circuitBreakerConfig = circuitBreakerConfig;
+        this.bulkheadConfig = bulkheadConfig;
         this.processor = processor;
         this.fallback = fallback;
-        this.fallbackViaNetwork = fallbackViaNetwork;
     }
 
     @Override
@@ -72,6 +76,56 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         return "resilience4j";
     }
 
+    @ManagedAttribute
+    public float getCircuitBreakerFailureRateThreshold() {
+        return circuitBreakerConfig.getFailureRateThreshold();
+    }
+
+    @ManagedAttribute
+    public float getCircuitBreakerSlowCallRateThreshold() {
+        return circuitBreakerConfig.getSlowCallRateThreshold();
+    }
+
+    @ManagedAttribute
+    public int getCircuitBreakerMinimumNumberOfCalls() {
+        return circuitBreakerConfig.getMinimumNumberOfCalls();
+    }
+
+    @ManagedAttribute
+    public int getCircuitBreakerPermittedNumberOfCallsInHalfOpenState() {
+        return circuitBreakerConfig.getPermittedNumberOfCallsInHalfOpenState();
+    }
+
+    @ManagedAttribute
+    public int getCircuitBreakerSlidingWindowSize() {
+        return circuitBreakerConfig.getSlidingWindowSize();
+    }
+
+    @ManagedAttribute
+    public String getCircuitBreakerSlidingWindowType() {
+        return circuitBreakerConfig.getSlidingWindowType().name();
+    }
+
+    @ManagedAttribute
+    public long getCircuitBreakerWaitDurationInOpenState() {
+        return circuitBreakerConfig.getWaitDurationInOpenState().getSeconds();
+    }
+
+    @ManagedAttribute
+    public boolean isCircuitBreakerTransitionFromOpenToHalfOpenEnabled() {
+        return circuitBreakerConfig.isAutomaticTransitionFromOpenToHalfOpenEnabled();
+    }
+
+    @ManagedAttribute
+    public boolean isCircuitBreakerWritableStackTraceEnabled() {
+        return circuitBreakerConfig.isWritableStackTraceEnabled();
+    }
+
+    @ManagedAttribute
+    public boolean isBulkheadEnabled() {
+        return bulkheadConfig != null;
+    }
+
     @Override
     public List<Processor> next() {
         if (!hasNext()) {
@@ -99,19 +153,23 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 //        Callable<String> callable = TimeLimiter.decorateFutureSupplier(TimeLimiter.of(Duration.ofMillis(500)), futureSupplier);
 //        String result = CircuitBreaker.decorateCheckedSupplier(cb, callable::call).apply();
 
-//        Bulkhead bh = Bulkhead.ofDefaults("ddd");
-//        BulkheadConfig.
-
 //                TimeLimiter time = TimeLimiter.of(Duration.ofSeconds(1));
 //        Supplier<Future<Exchange>> task2 = time.decorateFutureSupplier(() -> {
 //            task.get();
 //            Future
 //        });
 
-        CircuitBreaker cb = CircuitBreaker.of(id, config);
+        CircuitBreaker cb = CircuitBreaker.of(id, circuitBreakerConfig);
+
         Supplier<Exchange> task = CircuitBreaker.decorateSupplier(cb, new CircuitBreakerTask(processor, exchange));
+        Function<Throwable, Exchange> fallbackTask = new CircuitBreakerFallbackTask(fallback, exchange);
+        if (bulkheadConfig != null) {
+            Bulkhead bh = Bulkhead.of(id, bulkheadConfig);
+            task = Bulkhead.decorateSupplier(bh, task);
+        }
+
         Try.ofSupplier(task)
-                .recover(new CircuitBreakerFallbackTask(fallback, exchange))
+                .recover(fallbackTask)
                 .andFinally(() -> callback.done(false)).get();
 
         return false;
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 3704219..06399cd 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 
+import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 
 import org.apache.camel.CamelContext;
@@ -41,8 +42,9 @@ import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
+    // TODO: metrics with state of CB
+    // TODO: expose metrics as JMX on processor
     // TODO: Timeout
-    // TODO: Bulkhead for viaNetwork
 
     public ResilienceReifier(CircuitBreakerDefinition definition) {
         super(definition);
@@ -56,14 +58,18 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         if (definition.getOnFallback() != null) {
             fallback = ProcessorReifier.reifier(definition.getOnFallback()).createProcessor(routeContext);
         }
-
+        boolean fallbackViaNetwork = definition.getOnFallback() != null && definition.getOnFallback().isFallbackViaNetwork();
+        if (fallbackViaNetwork) {
+            throw new UnsupportedOperationException("camel-resilience4j does not support onFallbackViaNetwork");
+        }
         final Resilience4jConfigurationCommon config = buildResilience4jConfiguration(routeContext.getCamelContext());
-        CircuitBreakerConfig cfg = configureResilience4j(config);
+        CircuitBreakerConfig cbConfig = configureCircuitBreaker(config);
+        BulkheadConfig bhConfig = configureBulkHead(config);
 
-        return new ResilienceProcessor(cfg, processor, fallback, false);
+        return new ResilienceProcessor(cbConfig, bhConfig, processor, fallback);
     }
 
-    private CircuitBreakerConfig configureResilience4j(Resilience4jConfigurationCommon config) {
+    private CircuitBreakerConfig configureCircuitBreaker(Resilience4jConfigurationCommon config) {
         CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom();
         if (config.getAutomaticTransitionFromOpenToHalfOpenEnabled() != null) {
             builder.automaticTransitionFromOpenToHalfOpenEnabled(config.getAutomaticTransitionFromOpenToHalfOpenEnabled());
@@ -98,6 +104,21 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         return builder.build();
     }
 
+    private BulkheadConfig configureBulkHead(Resilience4jConfigurationCommon config) {
+        if (config.getBulkheadEnabled() == null || !config.getBulkheadEnabled()) {
+            return null;
+        }
+
+        BulkheadConfig.Builder builder = BulkheadConfig.custom();
+        if (config.getBulkheadMaxConcurrentCalls() != null) {
+            builder.maxConcurrentCalls(config.getBulkheadMaxConcurrentCalls());
+        }
+        if (config.getBulkheadMaxWaitDuration() != null) {
+            builder.maxWaitDuration(Duration.ofSeconds(config.getBulkheadMaxConcurrentCalls()));
+        }
+        return builder.build();
+    }
+
     // *******************************
     // Helpers
     // *******************************
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java
new file mode 100644
index 0000000..4b1046f
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.component.resilience4j;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ResilienceManagementTest extends CamelTestSupport {
+
+    @Override
+    protected boolean useJmx() {
+        return true;
+    }
+
+    protected MBeanServer getMBeanServer() {
+        return context.getManagementStrategy().getManagementAgent().getMBeanServer();
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        // look inside jmx
+        // get the stats for the route
+        MBeanServer mbeanServer = getMBeanServer();
+
+        // context name
+        String name = context.getManagementName();
+
+        // get the object name for the delayer
+        ObjectName on = ObjectName.getInstance("org.apache.camel:context=" + name + ",type=processors,name=\"myResilience\"");
+
+        // should be on start
+        String routeId = (String) mbeanServer.getAttribute(on, "RouteId");
+        assertEquals("start", routeId);
+
+        // should be id of the node
+        Integer num = (Integer) mbeanServer.getAttribute(on, "CircuitBreakerMinimumNumberOfCalls");
+        assertEquals("100", num.toString());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("start")
+                    .circuitBreaker().id("myResilience")
+                        .to("direct:foo")
+                    .onFallback()
+                        .transform().constant("Fallback message")
+                    .end()
+                    .to("mock:result");
+
+                from("direct:foo")
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
similarity index 88%
copy from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
copy to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
index 7f2ea21..69833b9 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
@@ -18,14 +18,12 @@ package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore
-public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
+public class ResilienceRouteBulkheadFallbackTest extends CamelTestSupport {
 
     @Test
-    public void testHystrix() throws Exception {
+    public void testResilience() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
         getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
         getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
@@ -42,9 +40,9 @@ public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
             public void configure() throws Exception {
                 from("direct:start")
                     .to("log:start")
-                    .circuitBreaker()
+                    .circuitBreaker().resilience4jConfiguration().bulkheadEnabled(true).end()
                         .throwException(new IllegalArgumentException("Forced"))
-                    .onFallbackViaNetwork()
+                    .onFallback()
                         .transform().constant("Fallback message")
                     .end()
                     .to("log:result")
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
similarity index 72%
copy from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
copy to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
index 7f2ea21..3368884 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
@@ -18,17 +18,15 @@ package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore
-public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
+public class ResilienceRouteBulkheadOkTest extends CamelTestSupport {
 
     @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+    public void testResilience() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
 
         template.sendBody("direct:start", "Hello World");
 
@@ -41,14 +39,17 @@ public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
             @Override
             public void configure() throws Exception {
                 from("direct:start")
-                    .to("log:start")
-                    .circuitBreaker()
-                        .throwException(new IllegalArgumentException("Forced"))
-                    .onFallbackViaNetwork()
+                    .circuitBreaker().resilience4jConfiguration().bulkheadEnabled(true).end()
+                        .to("direct:foo")
+                        .to("log:foo")
+                    .onFallback()
                         .transform().constant("Fallback message")
                     .end()
                     .to("log:result")
                     .to("mock:result");
+
+                from("direct:foo")
+                    .transform().constant("Bye World");
             }
         };
     }
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackViaNetworkTest.java
similarity index 73%
rename from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
rename to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackViaNetworkTest.java
index 7f2ea21..012c219 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteFallbackViaNetworkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackViaNetworkTest.java
@@ -18,21 +18,25 @@ package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore
-public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
+public class ResilienceRouteFallbackViaNetworkTest extends CamelTestSupport {
 
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
-
-        template.sendBody("direct:start", "Hello World");
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
 
-        assertMockEndpointsSatisfied();
+    @Test
+    public void testResilience() throws Exception {
+        try {
+            context.addRoutes(createRouteBuilder());
+            context.start();
+            fail("Should throw exception");
+        } catch (Exception e) {
+            assertIsInstanceOf(UnsupportedOperationException.class, e.getCause());
+            assertEquals("camel-resilience4j does not support onFallbackViaNetwork", e.getCause().getMessage());
+        }
     }
 
     @Override
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
index 3c5be79..771211d 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -26,51 +26,58 @@ import org.apache.camel.spi.Metadata;
 public class Resilience4jConfigurationCommon extends IdentifiedType {
 
     @XmlAttribute
-    @Metadata(defaultValue = "Camel")
-    private String groupKey;
+    @Metadata(label = "circuitbreaker")
+    private String configRef;
     @XmlAttribute
-    @Metadata(defaultValue = "50")
+    @Metadata(label = "circuitbreaker", defaultValue = "50")
     private Float failureRateThreshold;
     @XmlAttribute
-    @Metadata(defaultValue = "10")
+    @Metadata(label = "circuitbreaker", defaultValue = "10")
     private Integer permittedNumberOfCallsInHalfOpenState;
     @XmlAttribute
-    @Metadata(defaultValue = "100")
+    @Metadata(label = "circuitbreaker", defaultValue = "100")
     private Integer slidingWindowSize;
     @XmlAttribute
-    @Metadata(defaultValue = "COUNT_BASED", enums = "TIME_BASED,COUNT_BASED")
+    @Metadata(label = "circuitbreaker", defaultValue = "COUNT_BASED", enums = "TIME_BASED,COUNT_BASED")
     private String slidingWindowType;
     @XmlAttribute
-    @Metadata(defaultValue = "100")
+    @Metadata(label = "circuitbreaker", defaultValue = "100")
     private Integer minimumNumberOfCalls;
     @XmlAttribute
-    @Metadata(defaultValue = "true")
+    @Metadata(label = "circuitbreaker", defaultValue = "true")
     private Boolean writableStackTraceEnabled;
     @XmlAttribute
-    @Metadata(defaultValue = "60")
+    @Metadata(label = "circuitbreaker", defaultValue = "60")
     private Integer waitDurationInOpenState;
     @XmlAttribute
-    @Metadata(defaultValue = "false")
+    @Metadata(label = "circuitbreaker", defaultValue = "false")
     private Boolean automaticTransitionFromOpenToHalfOpenEnabled;
     @XmlAttribute
-    @Metadata(defaultValue = "100")
+    @Metadata(label = "circuitbreaker", defaultValue = "100")
     private Float slowCallRateThreshold;
     @XmlAttribute
-    @Metadata(defaultValue = "60")
+    @Metadata(label = "circuitbreaker", defaultValue = "60")
     private Integer slowCallDurationThreshold;
+    @Metadata(label = "bulkhead", defaultValue = "false")
+    private Boolean bulkheadEnabled;
+    @Metadata(label = "bulkhead", defaultValue = "25")
+    private Integer bulkheadMaxConcurrentCalls;
+    @Metadata(label = "bulkhead", defaultValue = "0")
+    private Integer bulkheadMaxWaitDuration;
 
     // Getter/Setter
     // -------------------------------------------------------------------------
 
-    public String getGroupKey() {
-        return groupKey;
+    public String getConfigRef() {
+        return configRef;
     }
 
     /**
-     * Sets the group key to use. The default value is Camel.
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
+     * to lookup and use from the registry.
      */
-    public void setGroupKey(String groupKey) {
-        this.groupKey = groupKey;
+    public void setConfigRef(String configRef) {
+        this.configRef = configRef;
     }
 
     public Float getFailureRateThreshold() {
@@ -215,4 +222,41 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
     public void setSlowCallDurationThreshold(Integer slowCallDurationThreshold) {
         this.slowCallDurationThreshold = slowCallDurationThreshold;
     }
+
+    public Boolean getBulkheadEnabled() {
+        return bulkheadEnabled;
+    }
+
+    /**
+     * Whether bulkhead is enabled or not on the circuit breaker.
+     */
+    public void setBulkheadEnabled(Boolean bulkheadEnabled) {
+        this.bulkheadEnabled = bulkheadEnabled;
+    }
+
+    public Integer getBulkheadMaxConcurrentCalls() {
+        return bulkheadMaxConcurrentCalls;
+    }
+
+    /**
+     * Configures the max amount of concurrent calls the bulkhead will support.
+     */
+    public void setBulkheadMaxConcurrentCalls(Integer bulkheadMaxConcurrentCalls) {
+        this.bulkheadMaxConcurrentCalls = bulkheadMaxConcurrentCalls;
+    }
+
+    public Integer getBulkheadMaxWaitDuration() {
+        return bulkheadMaxWaitDuration;
+    }
+
+    /**
+     * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry
+     * is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0.
+     * <p>
+     * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking
+     * an event-loop thread will most likely have a negative effect on application throughput.
+     */
+    public void setBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) {
+        this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
+    }
 }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
index 2275140..015feeb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -31,8 +31,6 @@ import org.apache.camel.spi.Metadata;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class Resilience4jConfigurationDefinition extends Resilience4jConfigurationCommon {
 
-    public static final String DEFAULT_GROUP_KEY = "Camel";
-
     @XmlTransient
     private CircuitBreakerDefinition parent;
 
@@ -47,10 +45,11 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
     // -------------------------------------------------------------------------
 
     /**
-     * Sets the group key to use. The default value is Camel.
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
+     * to lookup and use from the registry.
      */
-    public Resilience4jConfigurationDefinition groupKey(String groupKey) {
-        setGroupKey(groupKey);
+    public Resilience4jConfigurationDefinition configRef(String ref) {
+        setConfigRef(ref);
         return this;
     }
 
@@ -168,6 +167,34 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
     }
 
     /**
+     * Whether bulkhead is enabled or not on the circuit breaker.
+     */
+    public Resilience4jConfigurationDefinition bulkheadEnabled(Boolean bulkheadEnabled) {
+        setBulkheadEnabled(bulkheadEnabled);
+        return this;
+    }
+
+    /**
+     * Configures the max amount of concurrent calls the bulkhead will support.
+     */
+    public Resilience4jConfigurationDefinition bulkheadMaxConcurrentCalls(Integer bulkheadMaxConcurrentCalls) {
+        setBulkheadMaxWaitDuration(bulkheadMaxConcurrentCalls);
+        return this;
+    }
+
+    /**
+     * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry
+     * is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0.
+     * <p>
+     * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking
+     * an event-loop thread will most likely have a negative effect on application throughput.
+     */
+    public Resilience4jConfigurationDefinition bulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) {
+        setBulkheadMaxWaitDuration(bulkheadMaxWaitDuration);
+        return this;
+    }
+
+    /**
      * End of configuration.
      */
     public CircuitBreakerDefinition end() {
diff --git a/docs/user-manual/modules/ROOT/nav.adoc b/docs/user-manual/modules/ROOT/nav.adoc
index 6d5904d..719f335 100644
--- a/docs/user-manual/modules/ROOT/nav.adoc
+++ b/docs/user-manual/modules/ROOT/nav.adoc
@@ -102,6 +102,8 @@
  ** xref:removeProperty-eip.adoc[Remove Property EIP]
  ** xref:requestReply-eip.adoc[Request Reply]
  ** xref:resequence-eip.adoc[Resequence EIP]
+ ** xref:resilience4j-eip.adoc[Resilience4j EIP]
+ ** xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration EIP]
  ** xref:rollback-eip.adoc[Rollback EIP]
  ** xref:roundRobin-eip.adoc[Round Robin EIP]
  ** xref:routingSlip-eip.adoc[Routing Slip EIP]
diff --git a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc b/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
index 2cd1eb5..bd98db1 100644
--- a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
+++ b/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
@@ -114,11 +114,11 @@ You can find an example with the source code: https://github.com/apache/camel/tr
 
 See the xref:hystrix-component.adoc[Hystrix Component].
 
-== Camel's Error Handler and Hystrix EIP
+== Camel's Error Handler and Circuit Breaker EIP
 
-By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and
+By default the Circuit Breaker EIP handles errors by itself. This means if the circuit breaker is open and
 the message fails, then Camel's error handler is not reacting also.
-However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown:
+However, you can enable Camels error handler with circuit breaker by enabling the `inheritErrorHandler` option, as shown:
 
 [source,java]
 ----
@@ -127,7 +127,7 @@ errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDel
 
 from("direct:start")
     .to("log:start")
-    // turn on Camel's error handler on hystrix so it can do redeliveries
+    // turn on Camel's error handler on circuit breaker so Camel can do redeliveries
     .circuitBreaker().inheritErrorHandler(true)
         .to("mock:a")
         .throwException(new IllegalArgumentException("Forced"))
@@ -136,13 +136,13 @@ from("direct:start")
     .to("mock:result");
 ----
 
-This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded
+This example is from an unit test, where you can see the Circuit Breaker EIP block has been hardcoded
 to always fail by throwing an exception. Because the `inheritErrorHandler` has been enabled,
-then Camel's error handler will attempt to call the Hystrix EIP block again.
+then Camel's error handler will attempt to call the Circuit Breaker EIP block again.
 
 That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message
 (first time + 3 redeliveries).
 
-If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be
+If we turn off the `inheritErrorHandler` option (default) then the Circuit Breaker EIP will only be
 executed once because it handled the error itself.
 
diff --git a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc b/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
similarity index 56%
copy from docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
copy to docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
index 2cd1eb5..46a6a8c 100644
--- a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
+++ b/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
@@ -1,13 +1,13 @@
-[[hystrix-eip]]
-= Hystrix EIP
-:page-source: core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
+[[resilience4j-eip]]
+= Resilience4j EIP
+:page-source: core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
 
-*Available as of Camel 2.18*
+*Available as of Camel 3.0*
 
-The Hystrix EIP provides integration with Netflix https://github.com/Netflix/Hystrix[Hystrix] to be used as circuit breaker in the Camel routes. Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
+This component supports the Circuit Breaker EIP with the Resilience4j library.
 
 NOTE: Camel provides the Circuit Breaker EIP in the route model, which allows to plugin different implementations.
-Hystrix is one such implementation.
+Resilience4j is one such implementation.
 
 Maven users will need to add the following dependency to their pom.xml to use this EIP:
 
@@ -15,7 +15,7 @@ Maven users will need to add the following dependency to their pom.xml to use th
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
-    <artifactId>camel-hystrix</artifactId>
+    <artifactId>camel-resilience4j</artifactId>
     <version>x.x.x</version><!-- use the same version as your Camel core version -->
 </dependency>
 ----
@@ -23,26 +23,18 @@ Maven users will need to add the following dependency to their pom.xml to use th
 == Configuration options
 
 // eip options: START
-The Hystrix EIP supports 2 options which are listed below:
-
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfiguration Definition
-| *hystrixConfigurationRef* | Refers to a Hystrix configuration to use for configuring the Hystrix EIP. |  | String
-|===
 // eip options: END
 
-See xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] for all the configuration options on Hystrix EIP.
+See xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] for all the configuration options on Resilience Circuit Breaker.
 
 == Samples
 
-Below is an example route showing an Hystrix endpoint that protects against slow operation by falling back to the in-lined fallback route. By default the timeout request is just *1000ms* so the HTTP endpoint has to be fairly quick to succeed.
+Below is an example route showing a Resilience endpoint that protects against a downstream HTTP operation by falling back to the in-lined fallback route.
 [source,java]
 ----
 from("direct:start")
     .circuitBreaker()
-        .to("http://fooservice.com/slow")
+        .to("http://fooservice.com/faulty")
     .onFallback()
         .transform().constant("Fallback message")
     .end()
@@ -56,7 +48,7 @@ And in XML DSL:
   <route>
     <from uri="direct:start"/>
     <circuitBreaker>
-      <to uri="http://fooservice.com/slow"/>
+      <to uri="http://fooservice.com/faulty"/>
       <onFallback>
         <transform>
           <constant>Fallback message</constant>
@@ -68,9 +60,11 @@ And in XML DSL:
 </camelContext>
 ----
 
-== Configuring Hystrix
+== Configuring Resilienc4j
 
-You can fine-tune Hystrix by the many xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] options.
+You can fine-tune Resilience4j by the many xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] options.
+
+TODO: Update example!!!
 For example to use a 2 second execution timeout, you can do as follows:
 
 [source,java]
@@ -110,15 +104,15 @@ See xref:onFallback-eip.adoc[onFallback].
 
 You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-hystrix[camel-example-hystrix].
 
-== Using Hystrix with Spring Boot
+== Using Resilience4j with Spring Boot
 
-See the xref:hystrix-component.adoc[Hystrix Component].
+See the xref:components::resilience4j-component.adoc[Resilience4j Component].
 
-== Camel's Error Handler and Hystrix EIP
+== Camel's Error Handler and Circuit Breaker EIP
 
-By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and
+By default the Circuit Breaker EIP handles errors by itself. This means if the circuit breaker is open and
 the message fails, then Camel's error handler is not reacting also.
-However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown:
+However, you can enable Camels error handler with circuit breaker by enabling the `inheritErrorHandler` option, as shown:
 
 [source,java]
 ----
@@ -127,7 +121,7 @@ errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDel
 
 from("direct:start")
     .to("log:start")
-    // turn on Camel's error handler on hystrix so it can do redeliveries
+    // turn on Camel's error handler on circuit breaker so Camel can do redeliveries
     .circuitBreaker().inheritErrorHandler(true)
         .to("mock:a")
         .throwException(new IllegalArgumentException("Forced"))
@@ -136,13 +130,13 @@ from("direct:start")
     .to("mock:result");
 ----
 
-This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded
+This example is from an unit test, where you can see the Circuit Breaker EIP block has been hardcoded
 to always fail by throwing an exception. Because the `inheritErrorHandler` has been enabled,
-then Camel's error handler will attempt to call the Hystrix EIP block again.
+then Camel's error handler will attempt to call the Circuit Breaker EIP block again.
 
 That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message
 (first time + 3 redeliveries).
 
-If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be
+If we turn off the `inheritErrorHandler` option (default) then the Circuit Breaker EIP will only be
 executed once because it handled the error itself.
 
diff --git a/docs/user-manual/modules/ROOT/pages/resilience4jConfiguration-eip.adoc b/docs/user-manual/modules/ROOT/pages/resilience4jConfiguration-eip.adoc
new file mode 100644
index 0000000..997ee11
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/resilience4jConfiguration-eip.adoc
@@ -0,0 +1,7 @@
+[[resilience4jConfiguration-eip]]
+= Resilience4j Configuration EIP
+:page-source: core/camel-core-engine/src/main/docs/eips/resilience4jConfiguration-eip.adoc
+
+
+// eip options: START
+// eip options: END
diff --git a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
index 17a15bf..2d82d3f 100644
--- a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
@@ -2585,6 +2585,16 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-resilience4j-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-rest</artifactId>
         <version>${project.version}</version>
       </dependency>


[camel] 07/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit da3bf41f168026dd69b03ff0e3f911d630a1d36b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 09:04:50 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../component/resilience4j/ResilienceReifier.java  |   3 +
 .../org/apache/camel/main/BaseMainSupport.java     |   2 +-
 .../camel/main/MainConfigurationProperties.java    |   8 +
 .../main/Resilience4jConfigurationProperties.java  | 390 +++++++++++++++++++++
 4 files changed, 402 insertions(+), 1 deletion(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 06399cd..912fb3e 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -45,6 +45,9 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
     // TODO: metrics with state of CB
     // TODO: expose metrics as JMX on processor
     // TODO: Timeout
+    // TODO: thread pool bulkhead
+    // TODO: spring-boot allow to configure via resilience4j-spring-boot
+    // TODO: example
 
     public ResilienceReifier(CircuitBreakerDefinition definition) {
         super(definition);
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 542ed8c..a87c01b 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
@@ -642,7 +642,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
         // lookup and configure SPI beans
         DefaultConfigurationConfigurer.afterPropertiesSet(camelContext);
 
-        // now configure context/hystrix/rest with additional properties
+        // now configure context/hystrix/resilience4j/rest with additional properties
         Properties prop = camelContext.getPropertiesComponent().loadProperties(name -> name.startsWith("camel."));
 
         // load properties from ENV (override existing)
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index 433b18d..c5eca6d 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -35,6 +35,7 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties<
 
     // extended configuration
     private final HystrixConfigurationProperties hystrixConfigurationProperties = new HystrixConfigurationProperties(this);
+    private final Resilience4jConfigurationProperties resilience4jConfigurationProperties = new Resilience4jConfigurationProperties(this);
     private final RestConfigurationProperties restConfigurationProperties = new RestConfigurationProperties(this);
 
     // extended
@@ -48,6 +49,13 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties<
     }
 
     /**
+     * To configure Circuit Breaker EIP with Resilience4j
+     */
+    public Resilience4jConfigurationProperties resilience4j() {
+        return resilience4jConfigurationProperties;
+    }
+
+    /**
      * To configure Rest DSL
      */
     public RestConfigurationProperties rest() {
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
new file mode 100644
index 0000000..db9c7b8
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
@@ -0,0 +1,390 @@
+/*
+ * 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.main;
+
+/**
+ * Global configuration for Resilience EIP circuit breaker.
+ */
+public class Resilience4jConfigurationProperties {
+
+    private final MainConfigurationProperties parent;
+
+    private String configRef;
+    private Float failureRateThreshold;
+    private Integer permittedNumberOfCallsInHalfOpenState;
+    private Integer slidingWindowSize;
+    private String slidingWindowType;
+    private Integer minimumNumberOfCalls;
+    private Boolean writableStackTraceEnabled;
+    private Integer waitDurationInOpenState;
+    private Boolean automaticTransitionFromOpenToHalfOpenEnabled;
+    private Float slowCallRateThreshold;
+    private Integer slowCallDurationThreshold;
+    private Boolean bulkheadEnabled;
+    private Integer bulkheadMaxConcurrentCalls;
+    private Integer bulkheadMaxWaitDuration;
+
+    public Resilience4jConfigurationProperties(MainConfigurationProperties parent) {
+        this.parent = parent;
+    }
+
+    public MainConfigurationProperties end() {
+        return parent;
+    }
+
+    // getter and setters
+    // --------------------------------------------------------------
+
+    public String getConfigRef() {
+        return configRef;
+    }
+
+    /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
+     * to lookup and use from the registry.
+     */
+    public void setConfigRef(String configRef) {
+        this.configRef = configRef;
+    }
+
+    public Float getFailureRateThreshold() {
+        return failureRateThreshold;
+    }
+
+    /**
+     * Configures the failure rate threshold in percentage.
+     * If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage.
+     */
+    public void setFailureRateThreshold(Float failureRateThreshold) {
+        this.failureRateThreshold = failureRateThreshold;
+    }
+
+    public Integer getPermittedNumberOfCallsInHalfOpenState() {
+        return permittedNumberOfCallsInHalfOpenState;
+    }
+
+    /**
+     * Configures the number of permitted calls when the CircuitBreaker is half open.
+     * <p>
+     * The size must be greater than 0. Default size is 10.
+     */
+    public void setPermittedNumberOfCallsInHalfOpenState(Integer permittedNumberOfCallsInHalfOpenState) {
+        this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState;
+    }
+
+    public Integer getSlidingWindowSize() {
+        return slidingWindowSize;
+    }
+
+    /**
+     * Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * {@code slidingWindowSize} configures the size of the sliding window. Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     * <p>
+     * The {@code slidingWindowSize} must be greater than 0.
+     * The {@code minimumNumberOfCalls} must be greater than 0.
+     * If the slidingWindowType is COUNT_BASED, the {@code minimumNumberOfCalls} cannot be greater than {@code slidingWindowSize}.
+     * If the slidingWindowType is TIME_BASED, you can pick whatever you want.
+     *
+     * Default slidingWindowSize is 100.
+     */
+    public void setSlidingWindowSize(Integer slidingWindowSize) {
+        this.slidingWindowSize = slidingWindowSize;
+    }
+
+    public String getSlidingWindowType() {
+        return slidingWindowType;
+    }
+
+    /**
+     * Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     *
+     * Default slidingWindowType is COUNT_BASED.
+     */
+    public void setSlidingWindowType(String slidingWindowType) {
+        this.slidingWindowType = slidingWindowType;
+    }
+
+    public Integer getMinimumNumberOfCalls() {
+        return minimumNumberOfCalls;
+    }
+
+    /**
+     * Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.
+     * For example, if {@code minimumNumberOfCalls} is 10, then at least 10 calls must be recorded, before the failure rate can be calculated.
+     * If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed.
+     *
+     * Default minimumNumberOfCalls is 100
+     */
+    public void setMinimumNumberOfCalls(Integer minimumNumberOfCalls) {
+        this.minimumNumberOfCalls = minimumNumberOfCalls;
+    }
+
+    public Boolean getWritableStackTraceEnabled() {
+        return writableStackTraceEnabled;
+    }
+
+    /**
+     * Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array.
+     * This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).
+     */
+    public void setWritableStackTraceEnabled(Boolean writableStackTraceEnabled) {
+        this.writableStackTraceEnabled = writableStackTraceEnabled;
+    }
+
+    public Integer getWaitDurationInOpenState() {
+        return waitDurationInOpenState;
+    }
+
+    /**
+     * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.
+     * Default value is 60 seconds.
+     */
+    public void setWaitDurationInOpenState(Integer waitDurationInOpenState) {
+        this.waitDurationInOpenState = waitDurationInOpenState;
+    }
+
+    public Boolean getAutomaticTransitionFromOpenToHalfOpenEnabled() {
+        return automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    /**
+     * Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.
+     */
+    public void setAutomaticTransitionFromOpenToHalfOpenEnabled(Boolean automaticTransitionFromOpenToHalfOpenEnabled) {
+        this.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    public Float getSlowCallRateThreshold() {
+        return slowCallRateThreshold;
+    }
+
+    /**
+     * Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration.
+     * When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100.
+     * Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.
+     */
+    public void setSlowCallRateThreshold(Float slowCallRateThreshold) {
+        this.slowCallRateThreshold = slowCallRateThreshold;
+    }
+
+    public Integer getSlowCallDurationThreshold() {
+        return slowCallDurationThreshold;
+    }
+
+    /**
+     * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.
+     * Default value is 60 seconds.
+     */
+    public void setSlowCallDurationThreshold(Integer slowCallDurationThreshold) {
+        this.slowCallDurationThreshold = slowCallDurationThreshold;
+    }
+
+    public Boolean getBulkheadEnabled() {
+        return bulkheadEnabled;
+    }
+
+    /**
+     * Whether bulkhead is enabled or not on the circuit breaker.
+     */
+    public void setBulkheadEnabled(Boolean bulkheadEnabled) {
+        this.bulkheadEnabled = bulkheadEnabled;
+    }
+
+    public Integer getBulkheadMaxConcurrentCalls() {
+        return bulkheadMaxConcurrentCalls;
+    }
+
+    /**
+     * Configures the max amount of concurrent calls the bulkhead will support.
+     */
+    public void setBulkheadMaxConcurrentCalls(Integer bulkheadMaxConcurrentCalls) {
+        this.bulkheadMaxConcurrentCalls = bulkheadMaxConcurrentCalls;
+    }
+
+    public Integer getBulkheadMaxWaitDuration() {
+        return bulkheadMaxWaitDuration;
+    }
+
+    /**
+     * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry
+     * is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0.
+     * <p>
+     * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking
+     * an event-loop thread will most likely have a negative effect on application throughput.
+     */
+    public void setBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) {
+        this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
+    }
+
+    /**
+     * Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance
+     * to lookup and use from the registry.
+     */
+    public Resilience4jConfigurationProperties withConfigRef(String configRef) {
+        this.configRef = configRef;
+        return this;
+    }
+
+    /**
+     * Configures the failure rate threshold in percentage.
+     * If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage.
+     */
+    public Resilience4jConfigurationProperties withFailureRateThreshold(Float failureRateThreshold) {
+        this.failureRateThreshold = failureRateThreshold;
+        return this;
+    }
+
+    /**
+     * Configures the number of permitted calls when the CircuitBreaker is half open.
+     * <p>
+     * The size must be greater than 0. Default size is 10.
+     */
+    public Resilience4jConfigurationProperties withPermittedNumberOfCallsInHalfOpenState(Integer permittedNumberOfCallsInHalfOpenState) {
+        this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState;
+        return this;
+    }
+
+    /**
+     * Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * {@code slidingWindowSize} configures the size of the sliding window. Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     * <p>
+     * The {@code slidingWindowSize} must be greater than 0.
+     * The {@code minimumNumberOfCalls} must be greater than 0.
+     * If the slidingWindowType is COUNT_BASED, the {@code minimumNumberOfCalls} cannot be greater than {@code slidingWindowSize}.
+     * If the slidingWindowType is TIME_BASED, you can pick whatever you want.
+     *
+     * Default slidingWindowSize is 100.
+     */
+    public Resilience4jConfigurationProperties withSlidingWindowSize(Integer slidingWindowSize) {
+        this.slidingWindowSize = slidingWindowSize;
+        return this;
+    }
+
+    /**
+     * Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     *
+     * Default slidingWindowType is COUNT_BASED.
+     */
+    public Resilience4jConfigurationProperties withSlidingWindowType(String slidingWindowType) {
+        this.slidingWindowType = slidingWindowType;
+        return this;
+    }
+
+    /**
+     * Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.
+     * For example, if {@code minimumNumberOfCalls} is 10, then at least 10 calls must be recorded, before the failure rate can be calculated.
+     * If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed.
+     *
+     * Default minimumNumberOfCalls is 100
+     */
+    public Resilience4jConfigurationProperties withMinimumNumberOfCalls(Integer minimumNumberOfCalls) {
+        this.minimumNumberOfCalls = minimumNumberOfCalls;
+        return this;
+    }
+
+    /**
+     * Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array.
+     * This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).
+     */
+    public Resilience4jConfigurationProperties withWritableStackTraceEnabled(Boolean writableStackTraceEnabled) {
+        this.writableStackTraceEnabled = writableStackTraceEnabled;
+        return this;
+    }
+
+    /**
+     * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.
+     * Default value is 60 seconds.
+     */
+    public Resilience4jConfigurationProperties withWaitDurationInOpenState(Integer waitDurationInOpenState) {
+        this.waitDurationInOpenState = waitDurationInOpenState;
+        return this;
+    }
+
+    public Resilience4jConfigurationProperties withAutomaticTransitionFromOpenToHalfOpenEnabled(Boolean automaticTransitionFromOpenToHalfOpenEnabled) {
+        this.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled;
+        return this;
+    }
+
+    /**
+     * Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration.
+     * When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100.
+     * Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.
+     */
+    public Resilience4jConfigurationProperties withSlowCallRateThreshold(Float slowCallRateThreshold) {
+        this.slowCallRateThreshold = slowCallRateThreshold;
+        return this;
+    }
+
+    /**
+     * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.
+     * Default value is 60 seconds.
+     */
+    public Resilience4jConfigurationProperties withSlowCallDurationThreshold(Integer slowCallDurationThreshold) {
+        this.slowCallDurationThreshold = slowCallDurationThreshold;
+        return this;
+    }
+
+    /**
+     * Whether bulkhead is enabled or not on the circuit breaker.
+     */
+    public Resilience4jConfigurationProperties withBulkheadEnabled(Boolean bulkheadEnabled) {
+        this.bulkheadEnabled = bulkheadEnabled;
+        return this;
+    }
+
+    /**
+     * Configures the max amount of concurrent calls the bulkhead will support.
+     */
+    public Resilience4jConfigurationProperties withBulkheadMaxConcurrentCalls(Integer bulkheadMaxConcurrentCalls) {
+        this.bulkheadMaxConcurrentCalls = bulkheadMaxConcurrentCalls;
+        return this;
+    }
+
+    /**
+     * Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry
+     * is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0.
+     * <p>
+     * Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking
+     * an event-loop thread will most likely have a negative effect on application throughput.
+     */
+    public Resilience4jConfigurationProperties withBulkheadMaxWaitDuration(Integer bulkheadMaxWaitDuration) {
+        this.bulkheadMaxWaitDuration = bulkheadMaxWaitDuration;
+        return this;
+    }
+}


[camel] 08/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 1cd632f17774dd7c72c86df4d75ce3c9d18ff571
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 09:10:01 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../component/resilience4j/ResilienceReifier.java  |  1 +
 .../HystrixRouteConfigMaximumSizeTest.java         | 86 ----------------------
 .../resilience4j/HystrixRouteConfigTest.java       | 85 ---------------------
 ...java => ResilienceInheritErrorHandlerTest.java} |  6 +-
 .../SpringHystrixRouteConfigMaximumSizeTest.java   | 44 -----------
 .../SpringHystrixRouteConfigRefTest.java           | 44 -----------
 .../resilience4j/SpringHystrixRouteConfigTest.java | 44 -----------
 .../SpringHystrixRouteConfigMaximumSizeTest.xml    | 49 ------------
 .../SpringHystrixRouteConfigRefTest.xml            | 51 -------------
 .../resilience4j/SpringHystrixRouteConfigTest.xml  | 49 ------------
 .../camel-main-configuration-metadata.json         | 84 +++++++++++++++++++++
 11 files changed, 87 insertions(+), 456 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 912fb3e..a9b3d00 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -48,6 +48,7 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
     // TODO: thread pool bulkhead
     // TODO: spring-boot allow to configure via resilience4j-spring-boot
     // TODO: example
+    // TODO: camel-main - configure hystrix/resilience/rest via java code fluent builder (does it work)
 
     public ResilienceReifier(CircuitBreakerDefinition definition) {
         super(definition);
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java
deleted file mode 100644
index cc225fe..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigMaximumSizeTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.model.CircuitBreakerDefinition;
-import org.apache.camel.model.HystrixConfigurationDefinition;
-import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore
-public class HystrixRouteConfigMaximumSizeTest extends CamelTestSupport {
-
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-
-        template.sendBody("direct:start", "Hello World");
-
-        assertMockEndpointsSatisfied();
-    }
-    
-    @Test
-    public void testGroupKeyAndThreadPoolKeyConfigFlagsDoNotScrapHystrixConfiguration() throws Exception {
-        // dummy route
-        RouteBuilder rb = new RouteBuilder(context) {
-            @Override
-            public void configure() throws Exception {
-                from("direct:foo")
-                    .circuitBreaker()
-                        .hystrixConfiguration().groupKey("test2").metricsHealthSnapshotIntervalInMilliseconds(99999).end()
-                        .to("log:hello")
-                    .end();
-                
-            }
-        };
-        
-        rb.configure();
-        
-        RouteDefinition route = rb.getRouteCollection().getRoutes().get(0);
-        assertEquals(CircuitBreakerDefinition.class, route.getOutputs().get(0).getClass());
-        
-        HystrixConfigurationDefinition config = ((CircuitBreakerDefinition) route.getOutputs().get(0)).getHystrixConfiguration();
-        assertEquals("test2", config.getGroupKey());
-        assertEquals(99999, config.getMetricsHealthSnapshotIntervalInMilliseconds().intValue());
-    }
-    
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:start")
-                    .circuitBreaker()
-                        .hystrixConfiguration().groupKey("myCamelApp").requestLogEnabled(false).corePoolSize(5)
-                            .maximumSize(15).allowMaximumSizeToDivergeFromCoreSize(true)
-                        .end()
-                        .to("direct:foo")
-                    .onFallback()
-                        .transform().constant("Fallback message")
-                    .end()
-                    .to("mock:result");
-
-                from("direct:foo")
-                    .transform().constant("Bye World");
-            }
-        };
-    }
-
-}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.java
deleted file mode 100644
index dc47a32..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixRouteConfigTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.model.CircuitBreakerDefinition;
-import org.apache.camel.model.HystrixConfigurationDefinition;
-import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore
-public class HystrixRouteConfigTest extends CamelTestSupport {
-
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-
-        template.sendBody("direct:start", "Hello World");
-
-        assertMockEndpointsSatisfied();
-    }
-    
-    @Test
-    public void testGroupKeyAndThreadPoolKeyConfigFlagsDoNotScrapHystrixConfiguration() throws Exception {
-        // dummy route
-        RouteBuilder rb = new RouteBuilder(context) {
-            @Override
-            public void configure() throws Exception {
-                from("direct:foo")
-                    .circuitBreaker()
-                        .hystrixConfiguration().groupKey("test2").metricsHealthSnapshotIntervalInMilliseconds(99999).end()
-                        .to("log:hello")
-                    .end();
-                
-            }
-        };
-        
-        rb.configure();
-        
-        RouteDefinition route = rb.getRouteCollection().getRoutes().get(0);
-        assertEquals(CircuitBreakerDefinition.class, route.getOutputs().get(0).getClass());
-        
-        HystrixConfigurationDefinition config = ((CircuitBreakerDefinition) route.getOutputs().get(0)).getHystrixConfiguration();
-        assertEquals("test2", config.getGroupKey());
-        assertEquals(99999, config.getMetricsHealthSnapshotIntervalInMilliseconds().intValue());
-    }
-
-    
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:start")
-                    .circuitBreaker()
-                        .hystrixConfiguration().groupKey("myCamelApp").requestLogEnabled(false).corePoolSize(5).end()
-                        .to("direct:foo")
-                    .onFallback()
-                        .transform().constant("Fallback message")
-                    .end()
-                    .to("mock:result");
-
-                from("direct:foo")
-                    .transform().constant("Bye World");
-            }
-        };
-    }
-
-}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerTest.java
similarity index 93%
rename from components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java
rename to components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerTest.java
index d50e02d..0974ce4 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixInheritErrorHandlerTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerTest.java
@@ -18,14 +18,12 @@ package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore
-public class HystrixInheritErrorHandlerTest extends CamelTestSupport {
+public class ResilienceInheritErrorHandlerTest extends CamelTestSupport {
 
     @Test
-    public void testHystrix() throws Exception {
+    public void testResilience() throws Exception {
         getMockEndpoint("mock:a").expectedMessageCount(3 + 1);
         getMockEndpoint("mock:dead").expectedMessageCount(1);
         getMockEndpoint("mock:result").expectedMessageCount(0);
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java
deleted file mode 100644
index fabd88a..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import org.apache.camel.test.spring.CamelSpringTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.springframework.context.support.AbstractApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.test.annotation.DirtiesContext;
-
-@Ignore
-@DirtiesContext
-public class SpringHystrixRouteConfigMaximumSizeTest extends CamelSpringTestSupport {
-
-    @Override
-    protected AbstractApplicationContext createApplicationContext() {
-        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigMaximumSizeTest.xml");
-    }
-
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-
-        template.sendBody("direct:start", "Hello World");
-
-        assertMockEndpointsSatisfied();
-    }
-
-}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java
deleted file mode 100644
index 14eaae3..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import org.apache.camel.test.spring.CamelSpringTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.springframework.context.support.AbstractApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.test.annotation.DirtiesContext;
-
-@Ignore
-@DirtiesContext
-public class SpringHystrixRouteConfigRefTest extends CamelSpringTestSupport {
-
-    @Override
-    protected AbstractApplicationContext createApplicationContext() {
-        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigRefTest.xml");
-    }
-
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-
-        template.sendBody("direct:start", "Hello World");
-
-        assertMockEndpointsSatisfied();
-    }
-
-}
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java
deleted file mode 100644
index 72ec426..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import org.apache.camel.test.spring.CamelSpringTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.springframework.context.support.AbstractApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.test.annotation.DirtiesContext;
-
-@Ignore
-@DirtiesContext
-public class SpringHystrixRouteConfigTest extends CamelSpringTestSupport {
-
-    @Override
-    protected AbstractApplicationContext createApplicationContext() {
-        return new ClassPathXmlApplicationContext("org/apache/camel/component/hystrix/processor/SpringHystrixRouteConfigTest.xml");
-    }
-
-    @Test
-    public void testHystrix() throws Exception {
-        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-
-        template.sendBody("direct:start", "Hello World");
-
-        assertMockEndpointsSatisfied();
-    }
-
-}
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml
deleted file mode 100644
index 4d0aa78..0000000
--- a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigMaximumSizeTest.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?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.
-
--->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="
-		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
-
-  <camelContext xmlns="http://camel.apache.org/schema/spring">
-    <route>
-      <from uri="direct:start"/>
-      <circuitBreaker>
-        <hystrixConfiguration groupKey="myCamelApp" requestLogEnabled="false" corePoolSize="5" maximumSize="15" allowMaximumSizeToDivergeFromCoreSize="true"/>
-        <to uri="direct:foo"/>
-        <onFallback>
-          <transform>
-            <constant>Fallback message</constant>
-          </transform>
-        </onFallback>
-      </circuitBreaker>
-      <to uri="mock:result"/>
-    </route>
-
-    <route>
-      <from uri="direct:foo"/>
-      <transform>
-        <constant>Bye World</constant>
-      </transform>
-    </route>
-  </camelContext>
-
-</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml
deleted file mode 100644
index 40cdf25..0000000
--- a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigRefTest.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?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.
-
--->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="
-		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
-
-  <camelContext xmlns="http://camel.apache.org/schema/spring">
-
-    <hystrixConfiguration id="hysConfig" requestLogEnabled="false" corePoolSize="5"/>
-
-    <route>
-      <from uri="direct:start"/>
-      <circuitBreaker configurationRef="hysConfig">
-        <to uri="direct:foo"/>
-        <onFallback>
-          <transform>
-            <constant>Fallback message</constant>
-          </transform>
-        </onFallback>
-      </circuitBreaker>
-      <to uri="mock:result"/>
-    </route>
-
-    <route>
-      <from uri="direct:foo"/>
-      <transform>
-        <constant>Bye World</constant>
-      </transform>
-    </route>
-  </camelContext>
-
-</beans>
\ No newline at end of file
diff --git a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml b/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml
deleted file mode 100644
index 2c8a9a6..0000000
--- a/components/camel-resilience4j/src/test/resources/org/apache/camel/component/resilience4j/SpringHystrixRouteConfigTest.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?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.
-
--->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="
-		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">
-
-  <camelContext xmlns="http://camel.apache.org/schema/spring">
-    <route>
-      <from uri="direct:start"/>
-      <circuitBreaker>
-        <hystrixConfiguration groupKey="myCamelApp" requestLogEnabled="false" corePoolSize="5"/>
-        <to uri="direct:foo"/>
-        <onFallback>
-          <transform>
-            <constant>Fallback message</constant>
-          </transform>
-        </onFallback>
-      </circuitBreaker>
-      <to uri="mock:result"/>
-    </route>
-
-    <route>
-      <from uri="direct:foo"/>
-      <transform>
-        <constant>Bye World</constant>
-      </transform>
-    </route>
-  </camelContext>
-
-</beans>
\ No newline at end of file
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 84b2444..0713982 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -52,6 +52,12 @@
 			"defaultValue":"true"
 		},
 		{
+			"name":"camel.main.automatic-transition-from-open-to-half-open-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed."
+		},
+		{
 			"name":"camel.main.auto-startup",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -103,6 +109,30 @@
 			"description":"Sets the logging level used by bean introspection, logging activity of its usage. The default is TRACE."
 		},
 		{
+			"name":"camel.main.bulkhead-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Whether bulkhead is enabled or not on the circuit breaker."
+		},
+		{
+			"name":"camel.main.bulkhead-max-concurrent-calls",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the max amount of concurrent calls the bulkhead will support."
+		},
+		{
+			"name":"camel.main.bulkhead-max-wait-duration",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures a maximum amount of time which the calling thread will wait to enter the bulkhead. If bulkhead has space available, entry is guaranteed and immediate. If bulkhead is full, calling threads will contest for space, if it becomes available. maxWaitDuration can be set to 0. Note: for threads running on an event-loop or equivalent (rx computation pool, etc), setting maxWaitDuration to 0 is highly recommended. Blocking an event-loop thread will most likely have a ne [...]
+		},
+		{
+			"name":"camel.main.config-ref",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Refers to an existing io.github.resilience4j.circuitbreaker.CircuitBreakerConfig instance to lookup and use from the registry."
+		},
+		{
 			"name":"camel.main.consumer-template-cache-size",
 			"type":"int",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -158,6 +188,12 @@
 			"description":"Sets whether endpoint runtime statistics is enabled (gathers runtime usage of each incoming and outgoing endpoints). The default value is false."
 		},
 		{
+			"name":"camel.main.failure-rate-threshold",
+			"type":"java.lang.Float",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the failure rate threshold in percentage. If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage."
+		},
+		{
 			"name":"camel.main.file-configurations",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -248,6 +284,12 @@
 			"defaultValue":"true"
 		},
 		{
+			"name":"camel.main.minimum-number-of-calls",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate. For example, if minimumNumberOfCalls is 10, then at least 10 calls must be recorded, before the failure rate can be calculated. If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed. Default minimumNumberOfCalls is 100"
+		},
+		{
 			"name":"camel.main.name",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -260,6 +302,12 @@
 			"description":"Sets package names for scanning for org.apache.camel.builder.RouteBuilder classes as candidates to be included. If you are using Spring Boot then its instead recommended to use Spring Boots component scanning and annotate your route builder classes with Component. In other words only use this for Camel Main in standalone mode."
 		},
 		{
+			"name":"camel.main.permitted-number-of-calls-in-half-open-state",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the number of permitted calls when the CircuitBreaker is half open. The size must be greater than 0. Default size is 10."
+		},
+		{
 			"name":"camel.main.producer-template-cache-size",
 			"type":"int",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -320,6 +368,30 @@
 			"defaultValue":"300"
 		},
 		{
+			"name":"camel.main.sliding-window-size",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. slidingWindowSize configures the size of the sliding window. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. The slidingWindowSize m [...]
+		},
+		{
+			"name":"camel.main.sliding-window-type",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed. Sliding window can either be count-based or time-based. If slidingWindowType is COUNT_BASED, the last slidingWindowSize calls are recorded and aggregated. If slidingWindowType is TIME_BASED, the calls of the last slidingWindowSize seconds are recorded and aggregated. Default slidingWindowType is COUNT_BASED."
+		},
+		{
+			"name":"camel.main.slow-call-duration-threshold",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage. Default value is 60 seconds."
+		},
+		{
+			"name":"camel.main.slow-call-rate-threshold",
+			"type":"java.lang.Float",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration. When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls. The threshold must be greater than 0 and not greater than 100. Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold."
+		},
+		{
 			"name":"camel.main.stream-caching-any-spool-rules",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -417,6 +489,18 @@
 			"description":"To turn on MDC logging"
 		},
 		{
+			"name":"camel.main.wait-duration-in-open-state",
+			"type":"java.lang.Integer",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open. Default value is 60 seconds."
+		},
+		{
+			"name":"camel.main.writable-stack-trace-enabled",
+			"type":"java.lang.Boolean",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array. This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls)."
+		},
+		{
 			"name":"camel.main.xml-rests",
 			"type":"java.lang.String",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",


[camel] 21/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 008e02dd3937f2cec4152b6a287f6785c69173fc
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 09:22:37 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../component/resilience4j/ResilienceReifier.java  |   3 -
 .../org/apache/camel/main/BaseMainSupport.java     |   2 +-
 examples/camel-example-resilience4j/README.adoc    |  13 ++
 .../src/main/resources/application.properties      |   4 +-
 .../client/src/main/resources/log4j2.properties    |   2 -
 .../camel-example-resilience4j/client2/pom.xml     | 109 +++++++++++
 .../java/sample/camel/Client2Application.java}     |   9 +-
 .../src/main/java/sample/camel/Client2Route.java   |  42 +++++
 .../src/main/java/sample/camel/CounterBean.java}   |  15 +-
 .../src/main/resources/META-INF/LICENSE.txt        | 203 +++++++++++++++++++++
 .../client2/src/main/resources/META-INF/NOTICE.txt |  11 ++
 .../client2/src/main/resources/META-INF/beans.xml  |  20 ++
 .../src/main/resources/application.properties      |   6 +-
 .../src/main/resources/log4j2.properties           |   2 -
 examples/camel-example-resilience4j/pom.xml        |   1 +
 .../java/sample/camel/Service2Application.java     |   2 +-
 16 files changed, 413 insertions(+), 31 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index c7d31d8..00817f4 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -47,9 +47,6 @@ import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
-    // TODO: spring-boot allow to configure via resilience4j-spring-boot
-    // TODO: camel-main - configure hystrix/resilience/rest via java code fluent builder (does it work)
-
     public ResilienceReifier(CircuitBreakerDefinition definition) {
         super(definition);
     }
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 a87c01b..c1c8825 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
@@ -712,7 +712,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
                 resilience4j = new Resilience4jConfigurationDefinition();
                 model.setResilience4jConfiguration(resilience4j);
             }
-            setPropertiesOnTarget(camelContext, resilience4j, hystrixProperties, null, "camel.resilience4j.",
+            setPropertiesOnTarget(camelContext, resilience4j, resilience4jProperties, null, "camel.resilience4j.",
                     mainConfigurationProperties.isAutoConfigurationFailFast(), true, autoConfiguredProperties);
         }
         if (!restProperties.isEmpty()) {
diff --git a/examples/camel-example-resilience4j/README.adoc b/examples/camel-example-resilience4j/README.adoc
index 6330443..7cc1a75 100644
--- a/examples/camel-example-resilience4j/README.adoc
+++ b/examples/camel-example-resilience4j/README.adoc
@@ -50,12 +50,25 @@ $ mvn compile camel:run
 
 And then start the client that calls service1 every second.
 
+We have provided two clients, one is using Spring Boot, the other Camel Main.
+You can run either one of them.
+
+To use Spring Boot
+
 [source,sh]
 ----
 $ cd client
 $ mvn compile spring-boot:run
 ----
 
+Or to use Camel Main
+
+[source,sh]
+----
+$ cd client2
+$ mvn compile camel:run
+----
+
 You can then stop service1 and see that the client should fallback to
 call service2 in the Resilience EIP circuit breaker. And then start service
 1 again and see the Resilience EIP go back to normal.
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/application.properties b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
index eafb09b..bd20d5c 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/application.properties
+++ b/examples/camel-example-resilience4j/client/src/main/resources/application.properties
@@ -24,8 +24,8 @@ camel.resilience4j.minimum-number-of-calls=5
 camel.resilience4j.sliding-window-size=10
 camel.resilience4j.sliding-window-type=TIME_BASED
 camel.resilience4j.failure-rate-threshold=50
-# stay in open for 10s before switching back to half-open
-camel.resilience4j.wait-duration-in-open-state=10
+# stay in open for 20s before switching back to half-open
+camel.resilience4j.wait-duration-in-open-state=20
 
 # resilience4j logging
 #logging.level.org.apache.camel.component.resilience=DEBUG
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties b/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
index 6f76518..f02e7ae 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
+++ b/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
@@ -19,7 +19,5 @@ appender.stdout.type = Console
 appender.stdout.name = stdout
 appender.stdout.layout.type = PatternLayout
 appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
-logger.zipkin.name = org.apache.camel.zipkin
-logger.zipkin.level = DEBUG
 rootLogger.level = INFO
 rootLogger.appenderRef.stdout.ref = stdout
diff --git a/examples/camel-example-resilience4j/client2/pom.xml b/examples/camel-example-resilience4j/client2/pom.xml
new file mode 100644
index 0000000..2b12340
--- /dev/null
+++ b/examples/camel-example-resilience4j/client2/pom.xml
@@ -0,0 +1,109 @@
+<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel.example</groupId>
+        <artifactId>camel-example-resilience4j</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-example-resilience4j-client2</artifactId>
+    <name>Camel :: Example :: Resilience4j :: Client 2</name>
+    <description>An example showing how to use Resilience4j EIP as circuit breaker in Camel routes</description>
+
+    <!-- import Camel BOM -->
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-bom</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- camel-core -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-main</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-resilience4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-http</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+
+        <plugins>
+            <!-- allows the routes to be run via 'mvn camel:run' -->
+            <plugin>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-maven-plugin</artifactId>
+                <version>${project.version}</version>
+                <configuration>
+                    <mainClass>sample.camel.Client2Application</mainClass>
+                </configuration>
+                <dependencies>
+                    <!-- logging -->
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-api</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-core</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-slf4j-impl</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.logging.log4j</groupId>
+                        <artifactId>log4j-1.2-api</artifactId>
+                        <version>${log4j2-version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+
+    </build>
+
+</project>
diff --git a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Application.java
similarity index 78%
copy from examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
copy to examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Application.java
index 2fee2d9..e477d54 100644
--- a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
+++ b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Application.java
@@ -18,17 +18,16 @@ package sample.camel;
 
 import org.apache.camel.main.Main;
 
-//CHECKSTYLE:OFF
 /**
- * A Java main that runs Camel service 2
+ * A Camel Main application that runs the Camel Resilience client application that calls service 1 and service 2 (as fallback)
  */
-public class Service2Application {
+public class Client2Application {
 
     public static void main(String[] args) throws Exception {
         Main main = new Main();
-        main.addRoutesBuilder(new Service2Route());
+        main.addRoutesBuilder(new Client2Route());
+        main.bind("counterBean", new CounterBean());
         main.run();
     }
 
 }
-//CHECKSTYLE:ON
\ No newline at end of file
diff --git a/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Route.java b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Route.java
new file mode 100644
index 0000000..8e7065b
--- /dev/null
+++ b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/Client2Route.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 sample.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class Client2Route extends RouteBuilder {
+
+    @Override
+    public void configure() {
+        // you can configure the route rule with Java DSL here
+        from("timer:trigger?period=500").streamCaching()
+            .bean("counterBean")
+            .log(" Client request: ${body}")
+            .circuitBreaker()
+                // see application.properties how resilience is configured
+                .to("http://localhost:9090/service1")
+            //.onFallback()
+            // we use a fallback without network that provides a response message immediately
+            //    .transform().simple("Fallback ${body}")
+            .onFallback()
+                // we use fallback via network where we call a 2nd service
+                .to("http://localhost:7070/service2")
+            .end()
+            .log("Client response: ${body}");
+    }
+
+}
diff --git a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/CounterBean.java
similarity index 72%
copy from examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
copy to examples/camel-example-resilience4j/client2/src/main/java/sample/camel/CounterBean.java
index 2fee2d9..c6868c3 100644
--- a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
+++ b/examples/camel-example-resilience4j/client2/src/main/java/sample/camel/CounterBean.java
@@ -16,19 +16,12 @@
  */
 package sample.camel;
 
-import org.apache.camel.main.Main;
+public class CounterBean {
 
-//CHECKSTYLE:OFF
-/**
- * A Java main that runs Camel service 2
- */
-public class Service2Application {
+    private int counter;
 
-    public static void main(String[] args) throws Exception {
-        Main main = new Main();
-        main.addRoutesBuilder(new Service2Route());
-        main.run();
+    public String someMethod(String body) {
+        return "" + ++counter;
     }
 
 }
-//CHECKSTYLE:ON
\ No newline at end of file
diff --git a/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
diff --git a/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.
diff --git a/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/beans.xml b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..4d1f3eb
--- /dev/null
+++ b/examples/camel-example-resilience4j/client2/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,20 @@
+<?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.
+
+-->
+<beans/>
\ No newline at end of file
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/application.properties b/examples/camel-example-resilience4j/client2/src/main/resources/application.properties
similarity index 91%
copy from examples/camel-example-resilience4j/client/src/main/resources/application.properties
copy to examples/camel-example-resilience4j/client2/src/main/resources/application.properties
index eafb09b..3e60f28 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/application.properties
+++ b/examples/camel-example-resilience4j/client2/src/main/resources/application.properties
@@ -15,8 +15,6 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
-server.port=8080
-
 # configure resilience4j
 # when we have more than 5 requests per 10 seconds that 50%+ fails
 # then open circuit and call fallback immediately
@@ -24,8 +22,8 @@ camel.resilience4j.minimum-number-of-calls=5
 camel.resilience4j.sliding-window-size=10
 camel.resilience4j.sliding-window-type=TIME_BASED
 camel.resilience4j.failure-rate-threshold=50
-# stay in open for 10s before switching back to half-open
-camel.resilience4j.wait-duration-in-open-state=10
+# stay in open for 20s before switching back to half-open
+camel.resilience4j.wait-duration-in-open-state=20
 
 # resilience4j logging
 #logging.level.org.apache.camel.component.resilience=DEBUG
diff --git a/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties b/examples/camel-example-resilience4j/client2/src/main/resources/log4j2.properties
similarity index 94%
copy from examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
copy to examples/camel-example-resilience4j/client2/src/main/resources/log4j2.properties
index 6f76518..f02e7ae 100644
--- a/examples/camel-example-resilience4j/client/src/main/resources/log4j2.properties
+++ b/examples/camel-example-resilience4j/client2/src/main/resources/log4j2.properties
@@ -19,7 +19,5 @@ appender.stdout.type = Console
 appender.stdout.name = stdout
 appender.stdout.layout.type = PatternLayout
 appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
-logger.zipkin.name = org.apache.camel.zipkin
-logger.zipkin.level = DEBUG
 rootLogger.level = INFO
 rootLogger.appenderRef.stdout.ref = stdout
diff --git a/examples/camel-example-resilience4j/pom.xml b/examples/camel-example-resilience4j/pom.xml
index 4473c22..d52daa6 100644
--- a/examples/camel-example-resilience4j/pom.xml
+++ b/examples/camel-example-resilience4j/pom.xml
@@ -39,6 +39,7 @@
 
     <modules>
         <module>client</module>
+        <module>client2</module>
         <module>service1</module>
         <module>service2</module>
     </modules>
diff --git a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
index 2fee2d9..b0b3fcc 100644
--- a/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
+++ b/examples/camel-example-resilience4j/service2/src/main/java/sample/camel/Service2Application.java
@@ -20,7 +20,7 @@ import org.apache.camel.main.Main;
 
 //CHECKSTYLE:OFF
 /**
- * A Java main that runs Camel service 2
+ * A Java main that runs Camel service 2 using Camel Main
  */
 public class Service2Application {
 


[camel] 11/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit db108f86bc75aaf2420d979792b19fbc314417a8
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 11:46:21 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          | 158 ++++++++++++++++++++-
 .../component/resilience4j/ResilienceReifier.java  |   5 +-
 .../resilience4j/ResilienceManagementTest.java     |  14 +-
 3 files changed, 169 insertions(+), 8 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 50acd37..b4ab2ae 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -37,6 +37,7 @@ import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeExchangeException;
 import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
@@ -52,6 +53,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 
     private static final Logger LOG = LoggerFactory.getLogger(ResilienceProcessor.class);
 
+    private volatile CircuitBreaker circuitBreaker;
     private String id;
     private CircuitBreakerConfig circuitBreakerConfig;
     private BulkheadConfig bulkheadConfig;
@@ -83,6 +85,124 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         return "resilience4j";
     }
 
+    @ManagedAttribute(description = "Returns the current failure rate in percentage.")
+    public float getFailureRate() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getFailureRate();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current percentage of calls which were slower than a certain threshold.")
+    public float getSlowCallRate() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getSlowCallRate();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current total number of calls which were slower than a certain threshold.")
+    public int getNumberOfSlowCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfSlowCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current number of successful calls which were slower than a certain threshold.")
+    public int getNumberOfSlowSuccessfulCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfSlowCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current number of failed calls which were slower than a certain threshold.")
+    public int getNumberOfSlowFailedCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfSlowFailedCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current total number of buffered calls in the ring buffer.")
+    public int getNumberOfBufferedCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfBufferedCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current number of failed buffered calls in the ring buffer.")
+    public int getNumberOfFailedCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfFailedCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current number of successful buffered calls in the ring buffer")
+    public int getNumberOfSuccessfulCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfSuccessfulCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current number of not permitted calls, when the state is OPEN.")
+    public long getNumberOfNotPermittedCalls() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getMetrics().getNumberOfNotPermittedCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute(description = "Returns the current state of the circuit breaker")
+    public String getCircuitBreakerState() {
+        if (circuitBreaker != null) {
+            return circuitBreaker.getState().name();
+        } else {
+            return null;
+        }
+    }
+
+    @ManagedOperation(description = "Transitions the circuit breaker to CLOSED state.")
+    public void transitionToCloseState() {
+        if (circuitBreaker != null) {
+            circuitBreaker.transitionToClosedState();
+        }
+    }
+
+    @ManagedOperation(description = "Transitions the circuit breaker to OPEN state.")
+    public void transitionToOpenState() {
+        if (circuitBreaker != null) {
+            circuitBreaker.transitionToOpenState();
+        }
+    }
+
+    @ManagedOperation(description = "Transitions the circuit breaker to HALF_OPEN state.")
+    public void transitionToHalfOpenState() {
+        if (circuitBreaker != null) {
+            circuitBreaker.transitionToHalfOpenState();
+        }
+    }
+
+    @ManagedOperation(description = "Transitions the state machine to a FORCED_OPEN state, stopping state transition, metrics and event publishing.")
+    public void transitionToForceOpenState() {
+        if (circuitBreaker != null) {
+            circuitBreaker.transitionToForcedOpenState();
+        }
+    }
+
     @ManagedAttribute
     public float getCircuitBreakerFailureRateThreshold() {
         return circuitBreakerConfig.getFailureRateThreshold();
@@ -133,6 +253,38 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         return bulkheadConfig != null;
     }
 
+    @ManagedAttribute
+    public int getBulkheadMaxConcurrentCalls() {
+        if (bulkheadConfig != null) {
+            return bulkheadConfig.getMaxConcurrentCalls();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute()
+    public long getBulkheadMaxWaitDuration() {
+        if (bulkheadConfig != null) {
+            return bulkheadConfig.getMaxWaitDuration().toMillis();
+        } else {
+            return 0;
+        }
+    }
+
+    @ManagedAttribute
+    public boolean isTimeoutEnabled() {
+        return timeLimiterConfig != null;
+    }
+
+    @ManagedAttribute
+    public long getTimeoutDuration() {
+        if (timeLimiterConfig != null) {
+            return timeLimiterConfig.getTimeoutDuration().toMillis();
+        } else {
+            return 0;
+        }
+    }
+
     @Override
     public List<Processor> next() {
         if (!hasNext()) {
@@ -156,9 +308,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         // run this as if we run inside try .. catch so there is no regular Camel error handler
         exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true);
 
-        CircuitBreaker cb = CircuitBreaker.of(id, circuitBreakerConfig);
-
-        Callable<Exchange> task = CircuitBreaker.decorateCallable(cb, new CircuitBreakerTask(processor, exchange));
+        Callable<Exchange> task = CircuitBreaker.decorateCallable(circuitBreaker, new CircuitBreakerTask(processor, exchange));
         Function<Throwable, Exchange> fallbackTask = new CircuitBreakerFallbackTask(fallback, exchange);
         if (bulkheadConfig != null) {
             Bulkhead bh = Bulkhead.of(id, bulkheadConfig);
@@ -189,7 +339,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 
     @Override
     protected void doStart() throws Exception {
-        // noop
+        circuitBreaker = CircuitBreaker.of(id, circuitBreakerConfig);
     }
 
     @Override
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 95da2a4..da157fd 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -43,9 +43,8 @@ import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
-    // TODO: metrics with state of CB
-    // TODO: expose metrics as JMX on processor
     // TODO: thread pool bulkhead
+    // TODO: Configure timeout thread-pool globally
     // TODO: spring-boot allow to configure via resilience4j-spring-boot
     // TODO: example
     // TODO: camel-main - configure hystrix/resilience/rest via java code fluent builder (does it work)
@@ -119,7 +118,7 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
             builder.maxConcurrentCalls(config.getBulkheadMaxConcurrentCalls());
         }
         if (config.getBulkheadMaxWaitDuration() != null) {
-            builder.maxWaitDuration(Duration.ofSeconds(config.getBulkheadMaxConcurrentCalls()));
+            builder.maxWaitDuration(Duration.ofMillis(config.getBulkheadMaxWaitDuration()));
         }
         return builder.build();
     }
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java
index 4b1046f..388c4d5 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceManagementTest.java
@@ -56,9 +56,21 @@ public class ResilienceManagementTest extends CamelTestSupport {
         String routeId = (String) mbeanServer.getAttribute(on, "RouteId");
         assertEquals("start", routeId);
 
-        // should be id of the node
         Integer num = (Integer) mbeanServer.getAttribute(on, "CircuitBreakerMinimumNumberOfCalls");
         assertEquals("100", num.toString());
+
+        Integer totalRequests = (Integer) mbeanServer.getAttribute(on, "NumberOfSuccessfulCalls");
+        assertEquals(1, totalRequests.intValue());
+
+        Integer errorCount = (Integer) mbeanServer.getAttribute(on, "NumberOfFailedCalls");
+        assertEquals(0, errorCount.intValue());
+
+        String state = (String) mbeanServer.getAttribute(on, "CircuitBreakerState");
+        assertEquals("CLOSED", state);
+
+        mbeanServer.invoke(on, "transitionToOpenState", null, null);
+        state = (String) mbeanServer.getAttribute(on, "CircuitBreakerState");
+        assertEquals("OPEN", state);
     }
 
     @Override


[camel] 13/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit bc493f54ce930ee9d4d3ba8f94b80de1d3f9aab5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 12:41:07 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          | 19 +++--
 .../resilience4j/ResilienceRouteRejectedTest.java  | 80 ++++++++++++++++++++++
 2 files changed, 94 insertions(+), 5 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 1b1a039..1f6dbe3 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -28,6 +28,7 @@ import java.util.function.Supplier;
 
 import io.github.resilience4j.bulkhead.Bulkhead;
 import io.github.resilience4j.bulkhead.BulkheadConfig;
+import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 import io.github.resilience4j.timelimiter.TimeLimiter;
@@ -231,7 +232,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements CamelC
     }
 
     @ManagedOperation(description = "Transitions the state machine to a FORCED_OPEN state, stopping state transition, metrics and event publishing.")
-    public void transitionToForceOpenState() {
+    public void transitionToForcedOpenState() {
         if (circuitBreaker != null) {
             circuitBreaker.transitionToForcedOpenState();
         }
@@ -438,16 +439,27 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements CamelC
                     // the circuit breaker triggered a timeout (and there is no fallback) so lets mark the exchange as failed
                     exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
                     exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, false);
                     exchange.setProperty(CircuitBreakerConstants.RESPONSE_TIMED_OUT, true);
                     exchange.setException(throwable);
                     return exchange;
+                } else if (throwable instanceof CallNotPermittedException) {
+                    // the circuit breaker triggered a call rejected
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, true);
+                    exchange.setProperty(CircuitBreakerConstants.RESPONSE_REJECTED, true);
+                    return exchange;
                 } else {
                     // throw exception so resilient4j know it was a failure
                     throw RuntimeExchangeException.wrapRuntimeException(throwable);
                 }
             }
 
-            // fallback route is handling the exception
+            // fallback route is handling the exception so its short-circuited
+            exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+            exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
+            exchange.setProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, true);
 
             // store the last to endpoint as the failure endpoint
             if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
@@ -470,9 +482,6 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements CamelC
                 exchange.setException(e);
             }
 
-            exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
-            exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
-
             return exchange;
         }
     }
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteRejectedTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteRejectedTest.java
new file mode 100644
index 0000000..80b87bd
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteRejectedTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.component.resilience4j;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class ResilienceRouteRejectedTest extends CamelTestSupport {
+
+    @Override
+    protected boolean useJmx() {
+        return true;
+    }
+
+    protected MBeanServer getMBeanServer() {
+        return context.getManagementStrategy().getManagementAgent().getMBeanServer();
+    }
+
+    @Test
+    public void testResilience() throws Exception {
+        // look inside jmx
+        // get the stats for the route
+        MBeanServer mbeanServer = getMBeanServer();
+
+        // context name
+        String name = context.getManagementName();
+
+        ObjectName on = ObjectName.getInstance("org.apache.camel:context=" + name + ",type=processors,name=\"myResilience\"");
+
+        // force it into open state
+        mbeanServer.invoke(on, "transitionToForcedOpenState", null, null);
+        String state = (String) mbeanServer.getAttribute(on, "CircuitBreakerState");
+        assertEquals("FORCED_OPEN", state);
+
+        // send message which should get rejected, so the message is not changed
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker().id("myResilience")
+                        .to("direct:foo")
+                        .to("log:foo")
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+
+                from("direct:foo")
+                    .transform().constant("Bye World");
+            }
+        };
+    }
+
+}


[camel] 16/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit d59416ad1d50f9930885e4017cf1570fb8c92e4b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 05:54:32 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../src/main/docs/eips/circuitBreaker-eip.adoc     | 53 ----------------------
 .../src/main/docs/eips/hystrix-eip.adoc            |  4 +-
 .../src/main/docs/eips/resilience4j-eip.adoc       | 29 +++++++-----
 3 files changed, 20 insertions(+), 66 deletions(-)

diff --git a/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc b/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc
deleted file mode 100644
index 95d3056..0000000
--- a/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc
+++ /dev/null
@@ -1,53 +0,0 @@
-[[circuitBreaker-eip]]
-= Circuit Breaker EIP (deprecated)
-
-The Circuit Breaker load balancer is a stateful pattern that monitors all calls for certain exceptions. Initially the Circuit Breaker is in closed state and passes all messages. If there are failures and the threshold is reached, it moves to open state and rejects all calls until halfOpenAfter timeout is reached. After this timeout is reached, if there is a new call, it will pass and if the result is success the Circuit Breaker will move to closed state, or to open state if there was an error.
-When the circuit breaker is closed, it will throw a `java.util.concurrent.RejectedExecutionException`. This can then be caught to provide an alternate path for processing exchanges.
-
-// eip options: START
-The Circuit Breaker EIP supports 3 options which are listed below:
-
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *exception* | A list of class names for specific exceptions to monitor. If no exceptions is configured then all exceptions is monitored |  | List
-| *halfOpenAfter* | The timeout in millis to use as threshold to move state from closed to half-open or open state |  | Long
-| *threshold* | Number of previous failed messages to use as threshold to move state from closed to half-open or open state |  | Integer
-|===
-// eip options: END
-
-
-An example using Java DSL:
-[source,java]
-----
-from("direct:start")
-    .onException(RejectedExecutionException.class)
-        .handled(true)
-        .to("mock:serviceUnavailable")
-    .end()
-    .loadBalance()
-        .circuitBreaker(2, 1000L, MyCustomException.class)
-        .to("mock:service")
-    .end();
-----
-
-And the same example using Spring XML:
-[source,xml]
-----
-<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
-    <route>
-        <from uri="direct:start"/>
-        <onException>
-            <exception>java.util.concurrent.RejectedExecutionException</exception>
-            <handled><constant>true</constant></handled>
-            <to uri="mock:serviceUnavailable"/>
-        </onException>
-        <loadBalance>
-            <circuitBreaker threshold="2" halfOpenAfter="1000">
-                <exception>MyCustomException</exception>
-            </circuitBreaker>
-            <to uri="mock:service"/>
-        </loadBalance>
-    </route>
-</camelContext>
-----
diff --git a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
index b2d3a16..5323d15 100644
--- a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
@@ -10,7 +10,7 @@ Hystrix is one such implementation.
 
 Maven users will need to add the following dependency to their pom.xml to use this EIP:
 
-[source]
+[source,xml]
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
@@ -27,7 +27,7 @@ The Hystrix EIP supports 2 options which are listed below:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfiguration Definition
+| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfigurationDefinition
 | *hystrixConfigurationRef* | Refers to a Hystrix configuration to use for configuring the Hystrix EIP. |  | String
 |===
 // eip options: END
diff --git a/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
index 1137147..9a0ad62 100644
--- a/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
@@ -22,6 +22,14 @@ Maven users will need to add the following dependency to their pom.xml to use th
 == Configuration options
 
 // eip options: START
+The Hystrix EIP supports 2 options which are listed below:
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *resilienceConfiguration* | Configures the Resilience EIP Use end when configuration is complete, to return back to the Resilience EIP. |  | ResilienceConfigurationDefinition
+| *resilienceConfigurationRef* | Refers to a Resilience configuration to use for configuring the Resilience EIP. |  | String
+|===
 // eip options: END
 
 See xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] for all the configuration options on Resilience Circuit Breaker.
@@ -59,11 +67,10 @@ And in XML DSL:
 </camelContext>
 ----
 
-== Configuring Resilienc4j
+== Configuring Resilience4j
 
 You can fine-tune Resilience4j by the many xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] options.
 
-TODO: Update example!!!
 For example to use a 2 second execution timeout, you can do as follows:
 
 [source,java]
@@ -71,12 +78,12 @@ For example to use a 2 second execution timeout, you can do as follows:
 from("direct:start")
     .circuitBreaker()
         // use 2 second timeout
-        .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
-        .log("Hystrix processing start: ${threadName}")
+        .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end()
+        .log("Resilience processing start: ${threadName}")
         .toD("direct:${body}")
-        .log("Hystrix processing end: ${threadName}")
+        .log("Resilience processing end: ${threadName}")
     .end()
-    .log("After Hystrix ${body}");
+    .log("After Resilience ${body}");
 ----
 
 And in XML:
@@ -86,12 +93,12 @@ And in XML:
 <route>
   <from uri="direct:start"/>
   <circuitBreaker>
-    <hystrixConfiguration executionTimeoutInMilliseconds="2000"/>
-    <log message="Hystrix processing start: ${threadName}"/>
+    <resilience4jConfiguration timeoutEnabled="true" timeoutDuration="2000"/>
+    <log message="Resilience processing start: ${threadName}"/>
     <toD uri="direct:${body}"/>
-    <log message="Hystrix processing end: ${threadName}"/>
+    <log message="Resilience processing end: ${threadName}"/>
   </circuitBreaker>
-  <log message="After Hystrix: ${body}"/>
+  <log message="After Resilience: ${body}"/>
 </route>
 ----
 
@@ -101,7 +108,7 @@ See xref:onFallback-eip.adoc[onFallback].
 
 == Other examples
 
-You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-hystrix[camel-example-hystrix].
+You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-resilience4j[camel-example-resilience4j].
 
 == Using Resilience4j with Spring Boot
 


[camel] 05/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f3e97b122212c2427e91ffdbf36a0950cbb64514
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Nov 16 13:23:47 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          |  11 +--
 .../component/resilience4j/ResilienceReifier.java  | 104 ++++++++++++++++++++-
 2 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 1a6dbef..91fa38c 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -16,16 +16,13 @@
  */
 package org.apache.camel.component.resilience4j;
 
-import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
-import io.github.resilience4j.timelimiter.TimeLimiter;
+import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 import io.vavr.control.Try;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
@@ -48,11 +45,13 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
     private static final Logger LOG = LoggerFactory.getLogger(ResilienceProcessor.class);
 
     private String id;
+    private CircuitBreakerConfig config;
     private final Processor processor;
     private final Processor fallback;
     private final boolean fallbackViaNetwork;
 
-    public ResilienceProcessor(Processor processor, Processor fallback, boolean fallbackViaNetwork) {
+    public ResilienceProcessor(CircuitBreakerConfig config, Processor processor, Processor fallback, boolean fallbackViaNetwork) {
+        this.config = config;
         this.processor = processor;
         this.fallback = fallback;
         this.fallbackViaNetwork = fallbackViaNetwork;
@@ -109,7 +108,7 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 //            Future
 //        });
 
-        CircuitBreaker cb = CircuitBreaker.ofDefaults(id);
+        CircuitBreaker cb = CircuitBreaker.of(id, config);
         Supplier<Exchange> task = CircuitBreaker.decorateSupplier(cb, new CircuitBreakerTask(processor, exchange));
         Try.ofSupplier(task)
                 .recover(new CircuitBreakerFallbackTask(fallback, exchange))
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index 4bd1278..3704219 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -16,14 +16,31 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
 import org.apache.camel.model.CircuitBreakerDefinition;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.Resilience4jConfigurationCommon;
+import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.reifier.ProcessorReifier;
+import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.RouteContext;
+import org.apache.camel.support.PropertyBindingSupport;
+import org.apache.camel.util.function.Suppliers;
+
+import static org.apache.camel.support.CamelContextHelper.lookup;
+import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
-    // TODO: Resilience configuration in camel-core / model
     // TODO: Timeout
     // TODO: Bulkhead for viaNetwork
 
@@ -40,9 +57,90 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
             fallback = ProcessorReifier.reifier(definition.getOnFallback()).createProcessor(routeContext);
         }
 
-        final String id = getId(definition, routeContext);
+        final Resilience4jConfigurationCommon config = buildResilience4jConfiguration(routeContext.getCamelContext());
+        CircuitBreakerConfig cfg = configureResilience4j(config);
+
+        return new ResilienceProcessor(cfg, processor, fallback, false);
+    }
+
+    private CircuitBreakerConfig configureResilience4j(Resilience4jConfigurationCommon config) {
+        CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom();
+        if (config.getAutomaticTransitionFromOpenToHalfOpenEnabled() != null) {
+            builder.automaticTransitionFromOpenToHalfOpenEnabled(config.getAutomaticTransitionFromOpenToHalfOpenEnabled());
+        }
+        if (config.getFailureRateThreshold() != null) {
+            builder.failureRateThreshold(config.getFailureRateThreshold());
+        }
+        if (config.getMinimumNumberOfCalls() != null) {
+            builder.minimumNumberOfCalls(config.getMinimumNumberOfCalls());
+        }
+        if (config.getPermittedNumberOfCallsInHalfOpenState() != null) {
+            builder.permittedNumberOfCallsInHalfOpenState(config.getPermittedNumberOfCallsInHalfOpenState());
+        }
+        if (config.getSlidingWindowSize() != null) {
+            builder.slidingWindowSize(config.getSlidingWindowSize());
+        }
+        if (config.getSlidingWindowType() != null) {
+            builder.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.valueOf(config.getSlidingWindowType()));
+        }
+        if (config.getSlowCallDurationThreshold() != null) {
+            builder.slowCallDurationThreshold(Duration.ofSeconds(config.getSlowCallDurationThreshold()));
+        }
+        if (config.getSlowCallRateThreshold() != null) {
+            builder.slowCallRateThreshold(config.getSlowCallRateThreshold());
+        }
+        if (config.getWaitDurationInOpenState() != null) {
+            builder.waitDurationInOpenState(Duration.ofSeconds(config.getWaitDurationInOpenState()));
+        }
+        if (config.getWritableStackTraceEnabled() != null) {
+            builder.writableStackTraceEnabled(config.getWritableStackTraceEnabled());
+        }
+        return builder.build();
+    }
+
+    // *******************************
+    // Helpers
+    // *******************************
+
+    Resilience4jConfigurationDefinition buildResilience4jConfiguration(CamelContext camelContext) throws Exception {
+        Map<String, Object> properties = new HashMap<>();
+
+        // Extract properties from default configuration, the one configured on
+        // camel context takes the precedence over those in the registry
+        loadProperties(camelContext, properties, Suppliers.firstNotNull(
+                () -> camelContext.getExtension(Model.class).getResilience4jConfiguration(null),
+                () -> lookup(camelContext, "Camel", Resilience4jConfigurationDefinition.class))
+        );
+
+        // Extract properties from referenced configuration, the one configured
+        // on camel context takes the precedence over those in the registry
+        if (definition.getConfigurationRef() != null) {
+            final String ref = definition.getConfigurationRef();
+
+            loadProperties(camelContext, properties, Suppliers.firstNotNull(
+                    () -> camelContext.getExtension(Model.class).getResilience4jConfiguration(ref),
+                    () -> mandatoryLookup(camelContext, ref, Resilience4jConfigurationDefinition.class))
+            );
+        }
+
+        // Extract properties from local configuration
+        loadProperties(camelContext, properties, Optional.ofNullable(definition.getResilience4jConfiguration()));
+
+        // Extract properties from definition
+        BeanIntrospection beanIntrospection = camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+        beanIntrospection.getProperties(definition, properties, null, false);
+
+        Resilience4jConfigurationDefinition config = new Resilience4jConfigurationDefinition();
+
+        // Apply properties to a new configuration
+        PropertyBindingSupport.bindProperties(camelContext, config, properties);
+
+        return config;
+    }
 
-        return new ResilienceProcessor(processor, fallback, false);
+    private void loadProperties(CamelContext camelContext, Map<String, Object> properties, Optional<?> optional) {
+        BeanIntrospection beanIntrospection = camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection();
+        optional.ifPresent(bean -> beanIntrospection.getProperties(bean, properties, null, false));
     }
 
 }


[camel] 23/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a5025043331260be72f3141070313ab29f21ef2a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 10:00:12 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 examples/README.adoc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/examples/README.adoc b/examples/README.adoc
index b70d3fa..0a0a7f5 100644
--- a/examples/README.adoc
+++ b/examples/README.adoc
@@ -11,7 +11,7 @@ View the individual example READMEs for details.
 == Examples
 
 // examples: START
-Number of Examples: 117 (0 deprecated)
+Number of Examples: 118 (0 deprecated)
 
 [width="100%",cols="4,2,4",options="header"]
 |===
@@ -124,6 +124,8 @@ Number of Examples: 117 (0 deprecated)
 
 | link:camel-example-loan-broker-jms/README.adoc[Loan Broker JMS] (camel-example-loan-broker-jms) | EIP | An example that shows the EIP's loan broker demo using JMS
 
+| link:camel-example-resilience4j/README.adoc[Resilience4j] (camel-example-resilience4j) | EIP | An example showing how to use Resilience4j EIP as circuit breaker in Camel routes
+
 | link:camel-example-route-throttling/readme.md[Route Throttling] (camel-example-route-throttling) | EIP | A client-server example using JMS transport where we on the server side can throttle the Camel
         route dynamically based on the flow of messages
     


[camel] 14/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 1960eee0552ba7025aa37518fa16f625ebc650f2
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 13:25:07 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../hystrix/processor/HystrixConstants.java        |  7 -------
 .../hystrix/processor/HystrixProcessor.java        | 11 ++++++-----
 .../BlueprintHystrixRouteFallbackTest.java         |  5 +++--
 .../processor/BlueprintHystrixRouteOkTest.java     |  5 +++--
 .../processor/HystrixBadRequestExceptionTest.java  |  5 +++--
 .../hystrix/processor/HystrixCircuitOpenTest.java  | 12 +++++-------
 .../processor/HystrixRouteFallbackTest.java        |  5 +++--
 .../HystrixRouteFallbackViaNetworkTest.java        |  5 +++--
 .../hystrix/processor/HystrixRouteOkTest.java      |  5 +++--
 .../processor/SpringHystrixRouteFallbackTest.java  |  5 +++--
 .../processor/SpringHystrixRouteOkTest.java        |  5 +++--
 components/camel-resilience4j/pom.xml              | 22 +++++++++++++++++++---
 .../resilience4j/ResilienceProcessor.java          |  2 +-
 .../BlueprintResilienceRouteFallbackTest.java      |  1 +
 .../BlueprintResilienceRouteOkTest.java            |  1 +
 .../ResilienceRouteBulkheadFallbackTest.java       |  1 +
 .../ResilienceRouteBulkheadOkTest.java             |  1 +
 .../resilience4j/ResilienceRouteFallbackTest.java  |  1 +
 .../resilience4j/ResilienceRouteOkTest.java        |  1 +
 .../SpringResilienceRouteFallbackTest.java         |  1 +
 .../resilience4j/SpringResilienceRouteOkTest.java  |  1 +
 .../apache/camel/spi}/CircuitBreakerConstants.java |  4 +---
 parent/pom.xml                                     |  2 ++
 .../karaf/features/src/main/resources/features.xml | 11 +++++++++++
 .../apache/camel/itest/karaf/CamelHystrixTest.java | 20 ++++++++++++--------
 .../camel/itest/karaf/CamelResilience4jTest.java   | 22 ++++++++++++++--------
 26 files changed, 103 insertions(+), 58 deletions(-)

diff --git a/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixConstants.java b/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixConstants.java
index e9bcdfd..06fbb59 100644
--- a/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixConstants.java
+++ b/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixConstants.java
@@ -19,11 +19,4 @@ package org.apache.camel.component.hystrix.processor;
 public interface HystrixConstants {
     String DEFAULT_HYSTRIX_CONFIGURATION_ID = "hystrix-configuration";
 
-    // Hystrix EIP response properties
-    String HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION = "CamelHystrixSuccessfulExecution";
-    String HYSTRIX_RESPONSE_FROM_FALLBACK = "CamelHystrixResponseFromFallback";
-    String HYSTRIX_RESPONSE_SHORT_CIRCUITED = "CamelHystrixResponseShortCircuited";
-    String HYSTRIX_RESPONSE_TIMED_OUT = "CamelHystrixResponseTimedOut";
-    String HYSTRIX_RESPONSE_REJECTED = "CamelHystrixResponseRejected";
-
 }
diff --git a/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixProcessor.java b/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixProcessor.java
index b4c78cf..49c2425 100644
--- a/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixProcessor.java
+++ b/components/camel-hystrix/src/main/java/org/apache/camel/component/hystrix/processor/HystrixProcessor.java
@@ -30,6 +30,7 @@ import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
 import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
 
@@ -208,11 +209,11 @@ public class HystrixProcessor extends AsyncProcessorSupport implements Navigate<
     }
 
     private void commandResponse(Exchange exchange, HystrixCommand command) {
-        exchange.setProperty(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, command.isSuccessfulExecution());
-        exchange.setProperty(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, command.isResponseFromFallback());
-        exchange.setProperty(HystrixConstants.HYSTRIX_RESPONSE_SHORT_CIRCUITED, command.isResponseShortCircuited());
-        exchange.setProperty(HystrixConstants.HYSTRIX_RESPONSE_TIMED_OUT, command.isResponseTimedOut());
-        exchange.setProperty(HystrixConstants.HYSTRIX_RESPONSE_REJECTED, command.isResponseRejected());
+        exchange.setProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, command.isSuccessfulExecution());
+        exchange.setProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, command.isResponseFromFallback());
+        exchange.setProperty(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, command.isResponseShortCircuited());
+        exchange.setProperty(CircuitBreakerConstants.RESPONSE_TIMED_OUT, command.isResponseTimedOut());
+        exchange.setProperty(CircuitBreakerConstants.RESPONSE_REJECTED, command.isResponseRejected());
     }
 
     @Override
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteFallbackTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteFallbackTest.java
index 60f192a..05de4ff 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteFallbackTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteFallbackTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.hystrix.processor;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
 import org.junit.Test;
 
@@ -29,8 +30,8 @@ public class BlueprintHystrixRouteFallbackTest extends CamelBlueprintTestSupport
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteOkTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteOkTest.java
index 16a1ddd..e6333b2 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteOkTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/BlueprintHystrixRouteOkTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.hystrix.processor;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
 import org.junit.Test;
 
@@ -29,8 +30,8 @@ public class BlueprintHystrixRouteOkTest extends CamelBlueprintTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, true);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixBadRequestExceptionTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixBadRequestExceptionTest.java
index fc5abaf..fb37a4b 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixBadRequestExceptionTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixBadRequestExceptionTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.hystrix.processor;
 import com.netflix.hystrix.exception.HystrixBadRequestException;
 import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
@@ -31,8 +32,8 @@ public class HystrixBadRequestExceptionTest extends CamelTestSupport {
 
         Exchange out = template.send("direct:start", e -> e.getMessage().setBody("Hello World"));
         assertTrue(out.isFailed());
-        assertFalse(out.getProperty(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, boolean.class));
-        assertFalse(out.getProperty(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, boolean.class));
+        assertFalse(out.getProperty(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, boolean.class));
+        assertFalse(out.getProperty(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, boolean.class));
         assertTrue(out.getException() instanceof HystrixBadRequestException);
 
         assertMockEndpointsSatisfied();
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixCircuitOpenTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixCircuitOpenTest.java
index c362f76..2b793cc 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixCircuitOpenTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixCircuitOpenTest.java
@@ -23,14 +23,12 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.camel.component.hystrix.processor.HystrixConstants.HYSTRIX_RESPONSE_SHORT_CIRCUITED;
-import static org.apache.camel.component.hystrix.processor.HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION;
-
 public class HystrixCircuitOpenTest extends CamelTestSupport {
     public static final Integer REQUEST_VOLUME_THRESHOLD = 4;
     private static final Logger LOG = LoggerFactory.getLogger(HystrixCircuitOpenTest.class);
@@ -54,7 +52,7 @@ public class HystrixCircuitOpenTest extends CamelTestSupport {
         resetMocks();
 
         // notice this can be flaky due timing when using thread sleeps in unit tests
-        getMockEndpoint("mock:result").expectedPropertyReceived(HYSTRIX_RESPONSE_SHORT_CIRCUITED, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, true);
 
         route.throwException = false;
         try {
@@ -80,8 +78,8 @@ public class HystrixCircuitOpenTest extends CamelTestSupport {
 
         resetMocks();
 
-        getMockEndpoint("mock:result").expectedPropertyReceived(HYSTRIX_RESPONSE_SHORT_CIRCUITED, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
 
         template.requestBody("direct:start", "Request Body");
 
@@ -120,7 +118,7 @@ public class HystrixCircuitOpenTest extends CamelTestSupport {
                     })
                     .log("Hystrix processing end: ${threadName}")
                 .end()
-                .log(HYSTRIX_RESPONSE_SHORT_CIRCUITED + " = ${exchangeProperty." + HYSTRIX_RESPONSE_SHORT_CIRCUITED + "}")
+                .log(CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED + " = ${exchangeProperty." + CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED + "}")
                 .to("mock:result");
         }
     }
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackTest.java
index ee97733..04fcb0b 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.hystrix.processor;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
@@ -25,8 +26,8 @@ public class HystrixRouteFallbackTest extends CamelTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackViaNetworkTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackViaNetworkTest.java
index 7a5e683..7040ce4 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackViaNetworkTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteFallbackViaNetworkTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.hystrix.processor;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
@@ -25,8 +26,8 @@ public class HystrixRouteFallbackViaNetworkTest extends CamelTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteOkTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteOkTest.java
index e7faf1c..19a7f88 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteOkTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixRouteOkTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.hystrix.processor;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
@@ -25,8 +26,8 @@ public class HystrixRouteOkTest extends CamelTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, true);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteFallbackTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteFallbackTest.java
index b42d2cc..93346ef 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteFallbackTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteFallbackTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.hystrix.processor;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.spring.CamelSpringTestSupport;
 import org.junit.Test;
 import org.springframework.context.support.AbstractApplicationContext;
@@ -33,8 +34,8 @@ public class SpringHystrixRouteFallbackTest extends CamelSpringTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Fallback message");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, true);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteOkTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteOkTest.java
index 8e41820..c685dcf 100644
--- a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteOkTest.java
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/SpringHystrixRouteOkTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.hystrix.processor;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.spring.CamelSpringTestSupport;
 import org.junit.Test;
 import org.springframework.context.support.AbstractApplicationContext;
@@ -33,8 +34,8 @@ public class SpringHystrixRouteOkTest extends CamelSpringTestSupport {
     @Test
     public void testHystrix() throws Exception {
         getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_SUCCESSFUL_EXECUTION, true);
-        getMockEndpoint("mock:result").expectedPropertyReceived(HystrixConstants.HYSTRIX_RESPONSE_FROM_FALLBACK, false);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION, true);
+        getMockEndpoint("mock:result").expectedPropertyReceived(CircuitBreakerConstants.RESPONSE_FROM_FALLBACK, false);
 
         template.sendBody("direct:start", "Hello World");
 
diff --git a/components/camel-resilience4j/pom.xml b/components/camel-resilience4j/pom.xml
index 71f185f..a8e941e 100644
--- a/components/camel-resilience4j/pom.xml
+++ b/components/camel-resilience4j/pom.xml
@@ -48,17 +48,33 @@
         <dependency>
             <groupId>io.github.resilience4j</groupId>
             <artifactId>resilience4j-circuitbreaker</artifactId>
-            <version>1.1.0</version>
+            <version>${resilience4j-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.vavr</groupId>
+                    <artifactId>vavr</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>io.github.resilience4j</groupId>
             <artifactId>resilience4j-bulkhead</artifactId>
-            <version>1.1.0</version>
+            <version>${resilience4j-version}</version>
         </dependency>
         <dependency>
             <groupId>io.github.resilience4j</groupId>
             <artifactId>resilience4j-timelimiter</artifactId>
-            <version>1.1.0</version>
+            <version>${resilience4j-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.vavr</groupId>
+            <artifactId>vavr</artifactId>
+            <version>${vavr-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.vavr</groupId>
+            <artifactId>vavr-match</artifactId>
+            <version>${vavr-version}</version>
         </dependency>
 
         <!-- for testing -->
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 1f6dbe3..c936a9e 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -21,7 +21,6 @@ import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -44,6 +43,7 @@ import org.apache.camel.RuntimeExchangeException;
 import org.apache.camel.api.management.ManagedAttribute;
 import org.apache.camel.api.management.ManagedOperation;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
 import org.apache.camel.support.ExchangeHelper;
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java
index 0dac4de..8a9bf1b 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteFallbackTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java
index 5f064b3..62f71f9 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/BlueprintResilienceRouteOkTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
index 69833b9..8591c36 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadFallbackTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
index 3368884..d85c463 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteBulkheadOkTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java
index 6ae5c36..b3bb081 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteFallbackTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java
index 891d504..dc1d23d 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceRouteOkTest.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.resilience4j;
 
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Test;
 
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java
index 12792ad..53bff6c 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteFallbackTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.spring.CamelSpringTestSupport;
 import org.junit.Test;
 import org.springframework.context.support.AbstractApplicationContext;
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java
index c305804..07313b3 100644
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/SpringResilienceRouteOkTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import org.apache.camel.spi.CircuitBreakerConstants;
 import org.apache.camel.test.spring.CamelSpringTestSupport;
 import org.junit.Test;
 import org.springframework.context.support.AbstractApplicationContext;
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java b/core/camel-api/src/main/java/org/apache/camel/spi/CircuitBreakerConstants.java
similarity index 90%
copy from components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/CircuitBreakerConstants.java
index 0dcbb0c..dbaf377 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/CircuitBreakerConstants.java
@@ -14,9 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.resilience4j;
-
-// TODO: Make these as generic constants so we can use it for hystrix and resilience4j
+package org.apache.camel.spi;
 
 public interface CircuitBreakerConstants {
 
diff --git a/parent/pom.xml b/parent/pom.xml
index 4c02d65..78fb184 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -540,6 +540,7 @@
         <reflections-bundle-version>0.9.11_1</reflections-bundle-version>
         <regexp-bundle-version>1.4_1</regexp-bundle-version>
         <rescu-version>2.0.2</rescu-version>
+        <resilience4j-version>1.1.0</resilience4j-version>
         <rest-assured-version>4.1.2</rest-assured-version>
         <revapi-java-version>0.20.0</revapi-java-version>
         <revapi-maven-plugin-version>0.11.2</revapi-maven-plugin-version>
@@ -635,6 +636,7 @@
         <unix-socket-factory-bundle-version>1.0.0</unix-socket-factory-bundle-version>
         <validation-1-api-version>1.1.0.Final</validation-1-api-version>
         <validation-api-version>2.0.1.Final</validation-api-version>
+        <vavr-version>0.10.2</vavr-version>
         <velocity-bundle-version>1.7_6</velocity-bundle-version>
         <velocity-tools-version>2.0</velocity-tools-version>
         <velocity-version>2.0</velocity-version>
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index 2952094..759dacc 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -2067,6 +2067,17 @@
     <bundle dependency='true'>wrap:mvn:io.micrometer/micrometer-core/${micrometer-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-reactor/${project.version}</bundle>
   </feature>
+  <!-- does not work in OSGi: https://github.com/resilience4j/resilience4j/issues/750
+  <feature name='camel-resilience4j' version='${project.version}' start-level='50'>
+    <feature version='${project.version}'>camel-core</feature>
+    <bundle dependency='true'>mvn:io.github.resilience4j/resilience4j-core/${resilience4j-version}</bundle>
+    <bundle dependency='true'>mvn:io.github.resilience4j/resilience4j-circuitbreaker/${resilience4j-version}</bundle>
+    <bundle dependency='true'>mvn:io.github.resilience4j/resilience4j-bulkhead/${resilience4j-version}</bundle>
+    <bundle dependency='true'>mvn:io.github.resilience4j/resilience4j-timelimiter/${resilience4j-version}</bundle>
+    <bundle dependency='true'>mvn:io.vavr/vavr/${vavr-version}</bundle>
+    <bundle dependency='true'>mvn:io.vavr/vavr-match/${vavr-version}</bundle>
+    <bundle>mvn:org.apache.camel/camel-resilience4j/${project.version}</bundle>
+  </feature> -->
   <feature name='camel-rest-swagger' version='${project.version}' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
     <bundle dependency='true'>mvn:org.yaml/snakeyaml/${snakeyaml-version}</bundle>
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelHystrixTest.java
similarity index 58%
copy from components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
copy to tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelHystrixTest.java
index 0dcbb0c..79f8a50 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
+++ b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelHystrixTest.java
@@ -14,16 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.resilience4j;
+package org.apache.camel.itest.karaf;
 
-// TODO: Make these as generic constants so we can use it for hystrix and resilience4j
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
 
-public interface CircuitBreakerConstants {
+@RunWith(PaxExam.class)
+public class CamelHystrixTest extends BaseKarafTest {
 
-    String RESPONSE_SUCCESSFUL_EXECUTION = "CamelCircuitBreakerSuccessfulExecution";
-    String RESPONSE_FROM_FALLBACK = "CamelCircuitBreakerResponseFromFallback";
-    String RESPONSE_SHORT_CIRCUITED = "CamelCircuitBreakerResponseShortCircuited";
-    String RESPONSE_TIMED_OUT = "CamelCircuitBreakerResponseTimedOut";
-    String RESPONSE_REJECTED = "CamelCircuitBreakerResponseRejected";
+    public static final String COMPONENT = extractName(CamelHystrixTest.class);
+
+    @Test
+    public void test() throws Exception {
+        installCamelFeature(COMPONENT);
+    }
 
 }
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelResilience4jTest.java
similarity index 58%
rename from components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
rename to tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelResilience4jTest.java
index 0dcbb0c..d641fc7 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/CircuitBreakerConstants.java
+++ b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelResilience4jTest.java
@@ -14,16 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.resilience4j;
+package org.apache.camel.itest.karaf;
 
-// TODO: Make these as generic constants so we can use it for hystrix and resilience4j
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
 
-public interface CircuitBreakerConstants {
+@RunWith(PaxExam.class)
+@Ignore("Does not work in OSGi")
+public class CamelResilience4jTest extends BaseKarafTest {
 
-    String RESPONSE_SUCCESSFUL_EXECUTION = "CamelCircuitBreakerSuccessfulExecution";
-    String RESPONSE_FROM_FALLBACK = "CamelCircuitBreakerResponseFromFallback";
-    String RESPONSE_SHORT_CIRCUITED = "CamelCircuitBreakerResponseShortCircuited";
-    String RESPONSE_TIMED_OUT = "CamelCircuitBreakerResponseTimedOut";
-    String RESPONSE_REJECTED = "CamelCircuitBreakerResponseRejected";
+    public static final String COMPONENT = extractName(CamelResilience4jTest.class);
+
+    @Test
+    public void test() throws Exception {
+        installCamelFeature(COMPONENT);
+    }
 
 }


[camel] 03/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f42465fd9dcadf6fd8d80648cfb9dfb9d35fc065
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sat Nov 16 12:45:54 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          |   4 +
 .../src/main/docs/eips/hystrix-eip.adoc            |  14 +-
 .../{hystrix-eip.adoc => resilience4j-eip.adoc}    |  52 +++--
 .../docs/eips/resilience4jConfiguration-eip.adoc   |   6 +
 .../camel/model/CircuitBreakerDefinition.java      |  39 +++-
 .../model/Resilience4jConfigurationCommon.java     | 218 +++++++++++++++++++++
 .../model/Resilience4jConfigurationDefinition.java | 177 +++++++++++++++++
 7 files changed, 469 insertions(+), 41 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index 17be13f..1a6dbef 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -16,12 +16,16 @@
  */
 package org.apache.camel.component.resilience4j;
 
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
+import io.github.resilience4j.timelimiter.TimeLimiter;
 import io.vavr.control.Try;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
diff --git a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
index 3fa4d1b..b2d3a16 100644
--- a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
@@ -113,11 +113,11 @@ You can find an example with the source code: https://github.com/apache/camel/tr
 
 See the xref:hystrix-component.adoc[Hystrix Component].
 
-== Camel's Error Handler and Hystrix EIP
+== Camel's Error Handler and Circuit Breaker EIP
 
-By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and
+By default the Circuit Breaker EIP handles errors by itself. This means if the circuit breaker is open and
 the message fails, then Camel's error handler is not reacting also.
-However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown:
+However, you can enable Camels error handler with circuit breaker by enabling the `inheritErrorHandler` option, as shown:
 
 [source,java]
 ----
@@ -126,7 +126,7 @@ errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDel
 
 from("direct:start")
     .to("log:start")
-    // turn on Camel's error handler on hystrix so it can do redeliveries
+    // turn on Camel's error handler on circuit breaker so Camel can do redeliveries
     .circuitBreaker().inheritErrorHandler(true)
         .to("mock:a")
         .throwException(new IllegalArgumentException("Forced"))
@@ -135,13 +135,13 @@ from("direct:start")
     .to("mock:result");
 ----
 
-This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded
+This example is from an unit test, where you can see the Circuit Breaker EIP block has been hardcoded
 to always fail by throwing an exception. Because the `inheritErrorHandler` has been enabled,
-then Camel's error handler will attempt to call the Hystrix EIP block again.
+then Camel's error handler will attempt to call the Circuit Breaker EIP block again.
 
 That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message
 (first time + 3 redeliveries).
 
-If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be
+If we turn off the `inheritErrorHandler` option (default) then the Circuit Breaker EIP will only be
 executed once because it handled the error itself.
 
diff --git a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
similarity index 57%
copy from core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
copy to core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
index 3fa4d1b..1137147 100644
--- a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
@@ -1,12 +1,12 @@
-[[hystrix-eip]]
-= Hystrix EIP
+[[resilience4j-eip]]
+= Resilience4j EIP
 
-*Available as of Camel 2.18*
+*Available as of Camel 3.0*
 
-The Hystrix EIP provides integration with Netflix https://github.com/Netflix/Hystrix[Hystrix] to be used as circuit breaker in the Camel routes. Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
+This component supports the Circuit Breaker EIP with the Resilience4j library.
 
 NOTE: Camel provides the Circuit Breaker EIP in the route model, which allows to plugin different implementations.
-Hystrix is one such implementation.
+Resilience4j is one such implementation.
 
 Maven users will need to add the following dependency to their pom.xml to use this EIP:
 
@@ -14,7 +14,7 @@ Maven users will need to add the following dependency to their pom.xml to use th
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
-    <artifactId>camel-hystrix</artifactId>
+    <artifactId>camel-resilience4j</artifactId>
     <version>x.x.x</version><!-- use the same version as your Camel core version -->
 </dependency>
 ----
@@ -22,26 +22,18 @@ Maven users will need to add the following dependency to their pom.xml to use th
 == Configuration options
 
 // eip options: START
-The Hystrix EIP supports 2 options which are listed below:
-
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfiguration Definition
-| *hystrixConfigurationRef* | Refers to a Hystrix configuration to use for configuring the Hystrix EIP. |  | String
-|===
 // eip options: END
 
-See xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] for all the configuration options on Hystrix EIP.
+See xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] for all the configuration options on Resilience Circuit Breaker.
 
 == Samples
 
-Below is an example route showing an Hystrix endpoint that protects against slow operation by falling back to the in-lined fallback route. By default the timeout request is just *1000ms* so the HTTP endpoint has to be fairly quick to succeed.
+Below is an example route showing a Resilience endpoint that protects against a downstream HTTP operation by falling back to the in-lined fallback route.
 [source,java]
 ----
 from("direct:start")
     .circuitBreaker()
-        .to("http://fooservice.com/slow")
+        .to("http://fooservice.com/faulty")
     .onFallback()
         .transform().constant("Fallback message")
     .end()
@@ -55,7 +47,7 @@ And in XML DSL:
   <route>
     <from uri="direct:start"/>
     <circuitBreaker>
-      <to uri="http://fooservice.com/slow"/>
+      <to uri="http://fooservice.com/faulty"/>
       <onFallback>
         <transform>
           <constant>Fallback message</constant>
@@ -67,9 +59,11 @@ And in XML DSL:
 </camelContext>
 ----
 
-== Configuring Hystrix
+== Configuring Resilienc4j
 
-You can fine-tune Hystrix by the many xref:hystrixConfiguration-eip.adoc[Hystrix Configuration] options.
+You can fine-tune Resilience4j by the many xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] options.
+
+TODO: Update example!!!
 For example to use a 2 second execution timeout, you can do as follows:
 
 [source,java]
@@ -109,15 +103,15 @@ See xref:onFallback-eip.adoc[onFallback].
 
 You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-hystrix[camel-example-hystrix].
 
-== Using Hystrix with Spring Boot
+== Using Resilience4j with Spring Boot
 
-See the xref:hystrix-component.adoc[Hystrix Component].
+See the xref:components::resilience4j-component.adoc[Resilience4j Component].
 
-== Camel's Error Handler and Hystrix EIP
+== Camel's Error Handler and Circuit Breaker EIP
 
-By default the Hystrix EIP handles errors by itself. This means if the circuit breaker is open and
+By default the Circuit Breaker EIP handles errors by itself. This means if the circuit breaker is open and
 the message fails, then Camel's error handler is not reacting also.
-However, you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown:
+However, you can enable Camels error handler with circuit breaker by enabling the `inheritErrorHandler` option, as shown:
 
 [source,java]
 ----
@@ -126,7 +120,7 @@ errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDel
 
 from("direct:start")
     .to("log:start")
-    // turn on Camel's error handler on hystrix so it can do redeliveries
+    // turn on Camel's error handler on circuit breaker so Camel can do redeliveries
     .circuitBreaker().inheritErrorHandler(true)
         .to("mock:a")
         .throwException(new IllegalArgumentException("Forced"))
@@ -135,13 +129,13 @@ from("direct:start")
     .to("mock:result");
 ----
 
-This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded
+This example is from an unit test, where you can see the Circuit Breaker EIP block has been hardcoded
 to always fail by throwing an exception. Because the `inheritErrorHandler` has been enabled,
-then Camel's error handler will attempt to call the Hystrix EIP block again.
+then Camel's error handler will attempt to call the Circuit Breaker EIP block again.
 
 That means the `mock:a` endpoint will receive the message again, and a total of 1 + 3 = 4 message
 (first time + 3 redeliveries).
 
-If we turn off the `inheritErrorHandler` option (default) then the Hystrix EIP will only be
+If we turn off the `inheritErrorHandler` option (default) then the Circuit Breaker EIP will only be
 executed once because it handled the error itself.
 
diff --git a/core/camel-core-engine/src/main/docs/eips/resilience4jConfiguration-eip.adoc b/core/camel-core-engine/src/main/docs/eips/resilience4jConfiguration-eip.adoc
new file mode 100644
index 0000000..77f40f9
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/eips/resilience4jConfiguration-eip.adoc
@@ -0,0 +1,6 @@
+[[resilience4jConfiguration-eip]]
+= Resilience4j Configuration EIP
+
+
+// eip options: START
+// eip options: END
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
index c16e1b0..7a0769e 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
@@ -1,13 +1,13 @@
-/**
+/*
  * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
+ *
+ *      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.
@@ -36,6 +36,8 @@ public class CircuitBreakerDefinition extends ProcessorDefinition<CircuitBreaker
 
     @XmlElement
     private HystrixConfigurationDefinition hystrixConfiguration;
+    @XmlElement
+    private Resilience4jConfigurationDefinition resilience4jConfiguration;
     @XmlAttribute
     private String configurationRef;
     @XmlElementRef
@@ -122,12 +124,20 @@ public class CircuitBreakerDefinition extends ProcessorDefinition<CircuitBreaker
         this.hystrixConfiguration = hystrixConfiguration;
     }
 
+    public Resilience4jConfigurationCommon getResilience4jConfiguration() {
+        return resilience4jConfiguration;
+    }
+
+    public void setResilience4jConfiguration(Resilience4jConfigurationDefinition resilience4jConfiguration) {
+        this.resilience4jConfiguration = resilience4jConfiguration;
+    }
+
     public String getConfigurationRef() {
         return configurationRef;
     }
 
     /**
-     * Refers to a circuit breaker configuration (such as hystrix, resillient4j, or microprofile-fault-tolerance)
+     * Refers to a circuit breaker configuration (such as hystrix, resillience4j, or microprofile-fault-tolerance)
      * to use for configuring the circuit breaker EIP.
      */
     public void setConfigurationRef(String configurationRef) {
@@ -165,6 +175,25 @@ public class CircuitBreakerDefinition extends ProcessorDefinition<CircuitBreaker
     }
 
     /**
+     * Configures the circuit breaker to use Resilience4j.
+     * <p/>
+     * Use <tt>end</tt> when configuration is complete, to return back to the
+     * Circuit Breaker EIP.
+     */
+    public Resilience4jConfigurationDefinition resilience4jConfiguration() {
+        resilience4jConfiguration = resilience4jConfiguration == null ? new Resilience4jConfigurationDefinition(this) : resilience4jConfiguration;
+        return resilience4jConfiguration;
+    }
+
+    /**
+     * Configures the circuit breaker to use Resilience4j with the given configuration.
+     */
+    public CircuitBreakerDefinition resilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
+        resilience4jConfiguration = configuration;
+        return this;
+    }
+
+    /**
      * Refers to a configuration to use for configuring the circuit breaker.
      */
     public CircuitBreakerDefinition configuration(String ref) {
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
new file mode 100644
index 0000000..3c5be79
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -0,0 +1,218 @@
+/*
+ * 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.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+
+import org.apache.camel.spi.Metadata;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Resilience4jConfigurationCommon extends IdentifiedType {
+
+    @XmlAttribute
+    @Metadata(defaultValue = "Camel")
+    private String groupKey;
+    @XmlAttribute
+    @Metadata(defaultValue = "50")
+    private Float failureRateThreshold;
+    @XmlAttribute
+    @Metadata(defaultValue = "10")
+    private Integer permittedNumberOfCallsInHalfOpenState;
+    @XmlAttribute
+    @Metadata(defaultValue = "100")
+    private Integer slidingWindowSize;
+    @XmlAttribute
+    @Metadata(defaultValue = "COUNT_BASED", enums = "TIME_BASED,COUNT_BASED")
+    private String slidingWindowType;
+    @XmlAttribute
+    @Metadata(defaultValue = "100")
+    private Integer minimumNumberOfCalls;
+    @XmlAttribute
+    @Metadata(defaultValue = "true")
+    private Boolean writableStackTraceEnabled;
+    @XmlAttribute
+    @Metadata(defaultValue = "60")
+    private Integer waitDurationInOpenState;
+    @XmlAttribute
+    @Metadata(defaultValue = "false")
+    private Boolean automaticTransitionFromOpenToHalfOpenEnabled;
+    @XmlAttribute
+    @Metadata(defaultValue = "100")
+    private Float slowCallRateThreshold;
+    @XmlAttribute
+    @Metadata(defaultValue = "60")
+    private Integer slowCallDurationThreshold;
+
+    // Getter/Setter
+    // -------------------------------------------------------------------------
+
+    public String getGroupKey() {
+        return groupKey;
+    }
+
+    /**
+     * Sets the group key to use. The default value is Camel.
+     */
+    public void setGroupKey(String groupKey) {
+        this.groupKey = groupKey;
+    }
+
+    public Float getFailureRateThreshold() {
+        return failureRateThreshold;
+    }
+
+    /**
+     * Configures the failure rate threshold in percentage.
+     * If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage.
+     */
+    public void setFailureRateThreshold(Float failureRateThreshold) {
+        this.failureRateThreshold = failureRateThreshold;
+    }
+
+    public Integer getPermittedNumberOfCallsInHalfOpenState() {
+        return permittedNumberOfCallsInHalfOpenState;
+    }
+
+    /**
+     * Configures the number of permitted calls when the CircuitBreaker is half open.
+     * <p>
+     * The size must be greater than 0. Default size is 10.
+     */
+    public void setPermittedNumberOfCallsInHalfOpenState(Integer permittedNumberOfCallsInHalfOpenState) {
+        this.permittedNumberOfCallsInHalfOpenState = permittedNumberOfCallsInHalfOpenState;
+    }
+
+    public Integer getSlidingWindowSize() {
+        return slidingWindowSize;
+    }
+
+    /**
+     * Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * {@code slidingWindowSize} configures the size of the sliding window. Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     * <p>
+     * The {@code slidingWindowSize} must be greater than 0.
+     * The {@code minimumNumberOfCalls} must be greater than 0.
+     * If the slidingWindowType is COUNT_BASED, the {@code minimumNumberOfCalls} cannot be greater than {@code slidingWindowSize}.
+     * If the slidingWindowType is TIME_BASED, you can pick whatever you want.
+     *
+     * Default slidingWindowSize is 100.
+     */
+    public void setSlidingWindowSize(Integer slidingWindowSize) {
+        this.slidingWindowSize = slidingWindowSize;
+    }
+
+    public String getSlidingWindowType() {
+        return slidingWindowType;
+    }
+
+    /**
+     * Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     *
+     * Default slidingWindowType is COUNT_BASED.
+     */
+    public void setSlidingWindowType(String slidingWindowType) {
+        this.slidingWindowType = slidingWindowType;
+    }
+
+    public Integer getMinimumNumberOfCalls() {
+        return minimumNumberOfCalls;
+    }
+
+    /**
+     * Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.
+     * For example, if {@code minimumNumberOfCalls} is 10, then at least 10 calls must be recorded, before the failure rate can be calculated.
+     * If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed.
+     *
+     * Default minimumNumberOfCalls is 100
+     */
+    public void setMinimumNumberOfCalls(Integer minimumNumberOfCalls) {
+        this.minimumNumberOfCalls = minimumNumberOfCalls;
+    }
+
+    public Boolean getWritableStackTraceEnabled() {
+        return writableStackTraceEnabled;
+    }
+
+    /**
+     * Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array.
+     * This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).
+     */
+    public void setWritableStackTraceEnabled(Boolean writableStackTraceEnabled) {
+        this.writableStackTraceEnabled = writableStackTraceEnabled;
+    }
+
+    public Integer getWaitDurationInOpenState() {
+        return waitDurationInOpenState;
+    }
+
+    /**
+     * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.
+     * Default value is 60 seconds.
+     */
+    public void setWaitDurationInOpenState(Integer waitDurationInOpenState) {
+        this.waitDurationInOpenState = waitDurationInOpenState;
+    }
+
+    public Boolean getAutomaticTransitionFromOpenToHalfOpenEnabled() {
+        return automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    /**
+     * Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.
+     */
+    public void setAutomaticTransitionFromOpenToHalfOpenEnabled(Boolean automaticTransitionFromOpenToHalfOpenEnabled) {
+        this.automaticTransitionFromOpenToHalfOpenEnabled = automaticTransitionFromOpenToHalfOpenEnabled;
+    }
+
+    public Float getSlowCallRateThreshold() {
+        return slowCallRateThreshold;
+    }
+
+    /**
+     * Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration.
+     * When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100.
+     * Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.
+     */
+    public void setSlowCallRateThreshold(Float slowCallRateThreshold) {
+        this.slowCallRateThreshold = slowCallRateThreshold;
+    }
+
+    public Integer getSlowCallDurationThreshold() {
+        return slowCallDurationThreshold;
+    }
+
+    /**
+     * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.
+     * Default value is 60 seconds.
+     */
+    public void setSlowCallDurationThreshold(Integer slowCallDurationThreshold) {
+        this.slowCallDurationThreshold = slowCallDurationThreshold;
+    }
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
new file mode 100644
index 0000000..2275140
--- /dev/null
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -0,0 +1,177 @@
+/*
+ * 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.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Resilience4j Circuit Breaker EIP configuration
+ */
+@Metadata(label = "eip,routing,circuitbreaker")
+@XmlRootElement(name = "resilience4jConfiguration")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Resilience4jConfigurationDefinition extends Resilience4jConfigurationCommon {
+
+    public static final String DEFAULT_GROUP_KEY = "Camel";
+
+    @XmlTransient
+    private CircuitBreakerDefinition parent;
+
+    public Resilience4jConfigurationDefinition() {
+    }
+
+    public Resilience4jConfigurationDefinition(CircuitBreakerDefinition parent) {
+        this.parent = parent;
+    }
+
+    // Fluent API
+    // -------------------------------------------------------------------------
+
+    /**
+     * Sets the group key to use. The default value is Camel.
+     */
+    public Resilience4jConfigurationDefinition groupKey(String groupKey) {
+        setGroupKey(groupKey);
+        return this;
+    }
+
+    /**
+     * Configures the failure rate threshold in percentage.
+     * If the failure rate is equal or greater than the threshold the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100. Default value is 50 percentage.
+     */
+    public Resilience4jConfigurationDefinition failureRateThreshold(Float failureRateThreshold) {
+        setFailureRateThreshold(failureRateThreshold);
+        return this;
+    }
+
+    /**
+     * Configures the number of permitted calls when the CircuitBreaker is half open.
+     * <p>
+     * The size must be greater than 0. Default size is 10.
+     */
+    public Resilience4jConfigurationDefinition permittedNumberOfCallsInHalfOpenState(Integer permittedNumberOfCallsInHalfOpenState) {
+        setPermittedNumberOfCallsInHalfOpenState(permittedNumberOfCallsInHalfOpenState);
+        return this;
+    }
+
+    /**
+     * Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * {@code slidingWindowSize} configures the size of the sliding window. Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     * <p>
+     * The {@code slidingWindowSize} must be greater than 0.
+     * The {@code minimumNumberOfCalls} must be greater than 0.
+     * If the slidingWindowType is COUNT_BASED, the {@code minimumNumberOfCalls} cannot be greater than {@code slidingWindowSize}.
+     * If the slidingWindowType is TIME_BASED, you can pick whatever you want.
+     *
+     * Default slidingWindowSize is 100.
+     */
+    public Resilience4jConfigurationDefinition slidingWindowSize(Integer slidingWindowSize) {
+        setSlidingWindowSize(slidingWindowSize);
+        return this;
+    }
+
+    /**
+     * Configures the type of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
+     * Sliding window can either be count-based or time-based.
+     *
+     * If {@code slidingWindowType} is COUNT_BASED, the last {@code slidingWindowSize} calls are recorded and aggregated.
+     * If {@code slidingWindowType} is TIME_BASED, the calls of the last {@code slidingWindowSize} seconds are recorded and aggregated.
+     *
+     * Default slidingWindowType is COUNT_BASED.
+     */
+    public Resilience4jConfigurationDefinition slidingWindowType(String slidingWindowType) {
+        setSlidingWindowType(slidingWindowType);
+        return this;
+    }
+
+    /**
+     * Configures configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate.
+     * For example, if {@code minimumNumberOfCalls} is 10, then at least 10 calls must be recorded, before the failure rate can be calculated.
+     * If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed.
+     *
+     * Default minimumNumberOfCalls is 100
+     */
+    public Resilience4jConfigurationDefinition minimumNumberOfCalls(Integer minimumNumberOfCalls) {
+        setMinimumNumberOfCalls(minimumNumberOfCalls);
+        return this;
+    }
+
+    /**
+     * Enables writable stack traces. When set to false, Exception.getStackTrace returns a zero length array.
+     * This may be used to reduce log spam when the circuit breaker is open as the cause of the exceptions is already known (the circuit breaker is short-circuiting calls).
+     */
+    public Resilience4jConfigurationDefinition writableStackTraceEnabled(Boolean writableStackTraceEnabled) {
+        setWritableStackTraceEnabled(writableStackTraceEnabled);
+        return this;
+    }
+
+    /**
+     * Configures the wait duration (in seconds) which specifies how long the CircuitBreaker should stay open, before it switches to half open.
+     * Default value is 60 seconds.
+     */
+    public Resilience4jConfigurationDefinition waitDurationInOpenState(Integer waitDurationInOpenState) {
+        setWaitDurationInOpenState(waitDurationInOpenState);
+        return this;
+    }
+
+    /**
+     * Enables automatic transition from OPEN to HALF_OPEN state once the waitDurationInOpenState has passed.
+     */
+    public Resilience4jConfigurationDefinition automaticTransitionFromOpenToHalfOpenEnabled(Boolean automaticTransitionFromOpenToHalfOpenEnabled) {
+        setAutomaticTransitionFromOpenToHalfOpenEnabled(automaticTransitionFromOpenToHalfOpenEnabled);
+        return this;
+    }
+
+    /**
+     * Configures a threshold in percentage. The CircuitBreaker considers a call as slow when the call duration is greater than slowCallDurationThreshold(Duration.
+     * When the percentage of slow calls is equal or greater the threshold, the CircuitBreaker transitions to open and starts short-circuiting calls.
+     * <p>
+     * The threshold must be greater than 0 and not greater than 100.
+     * Default value is 100 percentage which means that all recorded calls must be slower than slowCallDurationThreshold.
+     */
+    public Resilience4jConfigurationDefinition slowCallRateThreshold(Float slowCallRateThreshold) {
+        setSlowCallRateThreshold(slowCallRateThreshold);
+        return this;
+    }
+
+    /**
+     * Configures the duration threshold (seconds) above which calls are considered as slow and increase the slow calls percentage.
+     * Default value is 60 seconds.
+     */
+    public Resilience4jConfigurationDefinition slowCallDurationThreshold(Integer slowCallDurationThreshold) {
+        setSlowCallDurationThreshold(slowCallDurationThreshold);
+        return this;
+    }
+
+    /**
+     * End of configuration.
+     */
+    public CircuitBreakerDefinition end() {
+        return parent;
+    }
+
+}


[camel] 12/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 2cf5880c599de47900bcb9dc616b96a64c65dc6f
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Nov 17 12:24:02 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../resilience4j/ResilienceProcessor.java          |  89 +++++++++++---
 .../component/resilience4j/ResilienceReifier.java  |  26 ++++-
 .../resilience4j/HystrixCircuitOpenTest.java       | 130 ---------------------
 .../ResilienceTimeoutThreadPoolTest.java           | 124 ++++++++++++++++++++
 .../model/Resilience4jConfigurationCommon.java     |  14 +++
 .../model/Resilience4jConfigurationDefinition.java |   9 ++
 .../main/Resilience4jConfigurationProperties.java  |  22 ++++
 .../camel-main-configuration-metadata.json         |   8 +-
 8 files changed, 272 insertions(+), 150 deletions(-)

diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
index b4ab2ae..1b1a039 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceProcessor.java
@@ -20,6 +20,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -32,6 +34,8 @@ import io.github.resilience4j.timelimiter.TimeLimiter;
 import io.github.resilience4j.timelimiter.TimeLimiterConfig;
 import io.vavr.control.Try;
 import org.apache.camel.AsyncCallback;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.Navigate;
 import org.apache.camel.Processor;
@@ -42,6 +46,7 @@ import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.support.AsyncProcessorSupport;
 import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,17 +54,20 @@ import org.slf4j.LoggerFactory;
  * Implementation of Circuit Breaker EIP using resilience4j.
  */
 @ManagedResource(description = "Managed Resilience Processor")
-public class ResilienceProcessor extends AsyncProcessorSupport implements Navigate<Processor>, org.apache.camel.Traceable, IdAware {
+public class ResilienceProcessor extends AsyncProcessorSupport implements CamelContextAware, Navigate<Processor>, org.apache.camel.Traceable, IdAware {
 
     private static final Logger LOG = LoggerFactory.getLogger(ResilienceProcessor.class);
 
     private volatile CircuitBreaker circuitBreaker;
+    private CamelContext camelContext;
     private String id;
-    private CircuitBreakerConfig circuitBreakerConfig;
-    private BulkheadConfig bulkheadConfig;
-    private TimeLimiterConfig timeLimiterConfig;
+    private final CircuitBreakerConfig circuitBreakerConfig;
+    private final BulkheadConfig bulkheadConfig;
+    private final TimeLimiterConfig timeLimiterConfig;
     private final Processor processor;
     private final Processor fallback;
+    private boolean shutdownExecutorService;
+    private ExecutorService executorService;
 
     public ResilienceProcessor(CircuitBreakerConfig circuitBreakerConfig, BulkheadConfig bulkheadConfig, TimeLimiterConfig timeLimiterConfig,
                                Processor processor, Processor fallback) {
@@ -71,6 +79,16 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
     }
 
     @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
     public String getId() {
         return id;
     }
@@ -80,6 +98,22 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         this.id = id;
     }
 
+    public boolean isShutdownExecutorService() {
+        return shutdownExecutorService;
+    }
+
+    public void setShutdownExecutorService(boolean shutdownExecutorService) {
+        this.shutdownExecutorService = shutdownExecutorService;
+    }
+
+    public ExecutorService getExecutorService() {
+        return executorService;
+    }
+
+    public void setExecutorService(ExecutorService executorService) {
+        this.executorService = executorService;
+    }
+
     @Override
     public String getTraceLabel() {
         return "resilience4j";
@@ -314,18 +348,17 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
             Bulkhead bh = Bulkhead.of(id, bulkheadConfig);
             task = Bulkhead.decorateCallable(bh, task);
         }
-        // timeout handling is more complex with thread-pools
-        // TODO: Allow to plugin custom thread-pool instead of JDKs
+
         if (timeLimiterConfig != null) {
-            final Callable<Exchange> future = task;
-            Supplier<CompletableFuture<Exchange>> futureSupplier = () -> CompletableFuture.supplyAsync(() -> {
-                try {
-                    return future.call();
-                } catch (Exception e) {
-                    exchange.setException(e);
-                }
-                return exchange;
-            });
+            // timeout handling is more complex with thread-pools
+            final CircuitBreakerTimeoutTask timeoutTask = new CircuitBreakerTimeoutTask(task, exchange);
+            Supplier<CompletableFuture<Exchange>> futureSupplier;
+            if (executorService == null) {
+                futureSupplier = () -> CompletableFuture.supplyAsync(timeoutTask::get);
+            } else {
+                futureSupplier = () -> CompletableFuture.supplyAsync(timeoutTask::get, executorService);
+            }
+
             TimeLimiter tl = TimeLimiter.of(id, timeLimiterConfig);
             task = TimeLimiter.decorateFutureSupplier(tl, futureSupplier);
         }
@@ -339,12 +372,15 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
 
     @Override
     protected void doStart() throws Exception {
+        ObjectHelper.notNull(camelContext, "CamelContext", this);
         circuitBreaker = CircuitBreaker.of(id, circuitBreakerConfig);
     }
 
     @Override
     protected void doStop() throws Exception {
-        // noop
+        if (shutdownExecutorService && executorService != null) {
+            getCamelContext().getExecutorServiceManager().shutdownNow(executorService);
+        }
     }
 
     private static class CircuitBreakerTask implements Callable<Exchange> {
@@ -441,4 +477,25 @@ public class ResilienceProcessor extends AsyncProcessorSupport implements Naviga
         }
     }
 
+    private static class CircuitBreakerTimeoutTask implements Supplier<Exchange>  {
+
+        private final Callable<Exchange> future;
+        private final Exchange exchange;
+
+        private CircuitBreakerTimeoutTask(Callable<Exchange> future, Exchange exchange) {
+            this.future = future;
+            this.exchange = exchange;
+        }
+
+        @Override
+        public Exchange get() {
+            try {
+                return future.call();
+            } catch (Exception e) {
+                exchange.setException(e);
+            }
+            return exchange;
+        }
+    }
+
 }
diff --git a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
index da157fd..e9aa90c 100644
--- a/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
+++ b/components/camel-resilience4j/src/main/java/org/apache/camel/component/resilience4j/ResilienceReifier.java
@@ -20,6 +20,7 @@ import java.time.Duration;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.ExecutorService;
 
 import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
@@ -30,6 +31,7 @@ import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
 import org.apache.camel.model.CircuitBreakerDefinition;
 import org.apache.camel.model.Model;
+import org.apache.camel.model.ProcessorDefinitionHelper;
 import org.apache.camel.model.Resilience4jConfigurationCommon;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.reifier.ProcessorReifier;
@@ -43,8 +45,6 @@ import static org.apache.camel.support.CamelContextHelper.mandatoryLookup;
 
 public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition> {
 
-    // TODO: thread pool bulkhead
-    // TODO: Configure timeout thread-pool globally
     // TODO: spring-boot allow to configure via resilience4j-spring-boot
     // TODO: example
     // TODO: camel-main - configure hystrix/resilience/rest via java code fluent builder (does it work)
@@ -70,7 +70,9 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         BulkheadConfig bhConfig = configureBulkHead(config);
         TimeLimiterConfig tlConfig = configureTimeLimiter(config);
 
-        return new ResilienceProcessor(cbConfig, bhConfig, tlConfig, processor, fallback);
+        ResilienceProcessor answer = new ResilienceProcessor(cbConfig, bhConfig, tlConfig, processor, fallback);
+        configureTimeoutExecutorService(answer, routeContext, config);
+        return answer;
     }
 
     private CircuitBreakerConfig configureCircuitBreaker(Resilience4jConfigurationCommon config) {
@@ -138,6 +140,24 @@ public class ResilienceReifier extends ProcessorReifier<CircuitBreakerDefinition
         return builder.build();
     }
 
+    private void configureTimeoutExecutorService(ResilienceProcessor processor, RouteContext routeContext, Resilience4jConfigurationCommon config) {
+        if (config.getTimeoutEnabled() == null || !config.getTimeoutEnabled()) {
+            return;
+        }
+
+        if (config.getTimeoutExecutorServiceRef() != null) {
+            String ref = config.getTimeoutExecutorServiceRef();
+            boolean shutdownThreadPool = false;
+            ExecutorService executorService = routeContext.lookup(ref, ExecutorService.class);
+            if (executorService == null) {
+                executorService = ProcessorDefinitionHelper.lookupExecutorServiceRef(routeContext, "CircuitBreaker", definition, ref);
+                shutdownThreadPool = true;
+            }
+            processor.setExecutorService(executorService);
+            processor.setShutdownExecutorService(shutdownThreadPool);
+        }
+    }
+
     // *******************************
     // Helpers
     // *******************************
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java
deleted file mode 100644
index e9e7bcf..0000000
--- a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/HystrixCircuitOpenTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.component.resilience4j;
-
-import java.io.IOException;
-
-import org.apache.camel.CamelExecutionException;
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.RoutesBuilder;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.camel.component.resilience4j.CircuitBreakerConstants.RESPONSE_SHORT_CIRCUITED;
-import static org.apache.camel.component.resilience4j.CircuitBreakerConstants.RESPONSE_SUCCESSFUL_EXECUTION;
-
-@Ignore
-public class HystrixCircuitOpenTest extends CamelTestSupport {
-    public static final Integer REQUEST_VOLUME_THRESHOLD = 4;
-    private static final Logger LOG = LoggerFactory.getLogger(HystrixCircuitOpenTest.class);
-
-    private HystrixExceptionRoute route = new HystrixExceptionRoute();
-
-    @Test
-    public void testCircuitOpen() throws Exception {
-        LOG.info("testCircuitOpen start");
-        // failing requests
-        route.throwException = true;
-        for (int i = 0; i < 2 * REQUEST_VOLUME_THRESHOLD; i++) {
-            try {
-                template.asyncRequestBody("direct:start", "Request Body");
-            } catch (CamelExecutionException e) {
-                LOG.info(e.toString());
-            }
-        }
-        Thread.sleep(1500);
-
-        resetMocks();
-
-        // notice this can be flaky due timing when using thread sleeps in unit tests
-        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SHORT_CIRCUITED, true);
-
-        route.throwException = false;
-        try {
-            template.requestBody("direct:start", "Request Body");
-            LOG.info("Instead circuit open expected");
-        } catch (CamelExecutionException e) {
-            LOG.info("Circuit open expected ", e);
-        }
-
-        assertMockEndpointsSatisfied();
-
-        // wait for the circuit to try an other request
-        Thread.sleep(500);
-        for (int i = 0; i < 2 * REQUEST_VOLUME_THRESHOLD; i++) {
-            try {
-                template.requestBody("direct:start", "Request Body");
-                LOG.info("Circuit has closed");
-            } catch (CamelExecutionException e) {
-                Thread.sleep(i * 100);
-                LOG.info("Circuit will be closed soon " + e.toString());
-            }
-        }
-
-        resetMocks();
-
-        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SHORT_CIRCUITED, false);
-        getMockEndpoint("mock:result").expectedPropertyReceived(RESPONSE_SUCCESSFUL_EXECUTION, true);
-
-        template.requestBody("direct:start", "Request Body");
-
-        assertMockEndpointsSatisfied();
-    }
-
-    @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return route;
-    }
-
-    class HystrixExceptionRoute extends RouteBuilder {
-        volatile boolean throwException = true;
-
-        @Override
-        public void configure() throws Exception {
-            from("direct:start")
-                .circuitBreaker()
-                    .hystrixConfiguration()
-                        .executionTimeoutInMilliseconds(100)
-                        .circuitBreakerRequestVolumeThreshold(REQUEST_VOLUME_THRESHOLD)
-                        .metricsRollingStatisticalWindowInMilliseconds(1000)
-                        .circuitBreakerSleepWindowInMilliseconds(2000)
-                    .end()
-                    .log("Hystrix processing start: ${threadName}")
-                    .process(new Processor() {
-                        @Override
-                        public void process(Exchange exchange) throws Exception {
-                            if (throwException) {
-                                LOG.info("Will throw exception");
-                                throw new IOException("Route has failed");
-                            } else {
-                                LOG.info("Will NOT throw exception");
-                            }
-                        }
-                    })
-                    .log("Hystrix processing end: ${threadName}")
-                .end()
-                .log(RESPONSE_SHORT_CIRCUITED + " = ${exchangeProperty." + RESPONSE_SHORT_CIRCUITED + "}")
-                .to("mock:result");
-        }
-    }
-}
-
diff --git a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutThreadPoolTest.java b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutThreadPoolTest.java
new file mode 100644
index 0000000..58e0c33
--- /dev/null
+++ b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceTimeoutThreadPoolTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.component.resilience4j;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+/**
+ * Resilience using timeout and custom thread pool with Java DSL
+ */
+public class ResilienceTimeoutThreadPoolTest extends CamelTestSupport {
+
+    @BindToRegistry
+    public ExecutorService myThreadPool() {
+        return context().getExecutorServiceManager().newFixedThreadPool(this, "myThreadPool", 2);
+    }
+
+    @Test
+    public void testFast() throws Exception {
+        // this calls the fast route and therefore we get a response
+        Object out = template.requestBody("direct:start", "fast");
+        assertEquals("Fast response", out);
+
+
+        ThreadPoolExecutor pte = context().getRegistry().lookupByNameAndType("myThreadPool", ThreadPoolExecutor.class);
+        assertNotNull(pte);
+        assertEquals(2, pte.getCorePoolSize());
+        assertEquals(1, pte.getCompletedTaskCount());
+
+        assertFalse(pte.isShutdown());
+    }
+
+    @Test
+    public void testSlow() throws Exception {
+        // this calls the slow route and therefore causes a timeout which triggers an exception
+        try {
+            template.requestBody("direct:start", "slow");
+            fail("Should fail due to timeout");
+        } catch (Exception e) {
+            // expected a timeout
+            assertIsInstanceOf(TimeoutException.class, e.getCause());
+        }
+
+        ThreadPoolExecutor pte = context().getRegistry().lookupByNameAndType("myThreadPool", ThreadPoolExecutor.class);
+        assertNotNull(pte);
+        assertEquals(2, pte.getCorePoolSize());
+        assertEquals(0, pte.getCompletedTaskCount());
+        assertEquals(1, pte.getActiveCount());
+
+        // stop camel and thread pool is also stopped
+        context().stop();
+
+        assertTrue(pte.isShutdown());
+    }
+
+    @Test
+    public void testSlowLoop() throws Exception {
+        // this calls the slow route and therefore causes a timeout which triggers an exception
+        for (int i = 0; i < 10; i++) {
+            try {
+                log.info(">>> test run " + i + " <<<");
+                template.requestBody("direct:start", "slow");
+                fail("Should fail due to timeout");
+            } catch (Exception e) {
+                // expected a timeout
+                assertIsInstanceOf(TimeoutException.class, e.getCause());
+            }
+        }
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .circuitBreaker()
+                        // enable and use 2 second timeout
+                        .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).timeoutExecutorServiceRef("myThreadPool").end()
+                        .log("Resilience processing start: ${threadName}")
+                        .toD("direct:${body}")
+                        .log("Resilience processing end: ${threadName}")
+                    .end()
+                    .log("After Resilience ${body}");
+
+                from("direct:fast")
+                    // this is a fast route and takes 1 second to respond
+                    .log("Fast processing start: ${threadName}")
+                    .delay(1000)
+                    .transform().constant("Fast response")
+                    .log("Fast processing end: ${threadName}");
+
+                from("direct:slow")
+                    // this is a slow route and takes 3 second to respond
+                    .log("Slow processing start: ${threadName}")
+                    .delay(3000)
+                    .transform().constant("Slow response")
+                    .log("Slow processing end: ${threadName}");
+            }
+        };
+    }
+
+}
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
index 208f8b0..decdd34 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationCommon.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.model;
 
+import java.util.concurrent.ForkJoinPool;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
@@ -66,6 +67,8 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
     private Integer bulkheadMaxWaitDuration;
     @Metadata(label = "timeout", defaultValue = "false")
     private Boolean timeoutEnabled;
+    @Metadata(label = "timeout")
+    private String timeoutExecutorServiceRef;
     @Metadata(label = "timeout", defaultValue = "1000")
     private Integer timeoutDuration;
     @Metadata(label = "timeout", defaultValue = "true")
@@ -279,6 +282,17 @@ public class Resilience4jConfigurationCommon extends IdentifiedType {
         this.timeoutEnabled = timeoutEnabled;
     }
 
+    public String getTimeoutExecutorServiceRef() {
+        return timeoutExecutorServiceRef;
+    }
+
+    /**
+     * References to a custom thread pool to use when timeout is enabled (uses {@link ForkJoinPool#commonPool()} by default)
+     */
+    public void setTimeoutExecutorServiceRef(String timeoutExecutorServiceRef) {
+        this.timeoutExecutorServiceRef = timeoutExecutorServiceRef;
+    }
+
     public Integer getTimeoutDuration() {
         return timeoutDuration;
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
index 76eadb0..54d4f0d 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/model/Resilience4jConfigurationDefinition.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.model;
 
+import java.util.concurrent.ForkJoinPool;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -205,6 +206,14 @@ public class Resilience4jConfigurationDefinition extends Resilience4jConfigurati
     }
 
     /**
+     * References to a custom thread pool to use when timeout is enabled (uses {@link ForkJoinPool#commonPool()} by default)
+     */
+    public Resilience4jConfigurationDefinition timeoutExecutorServiceRef(String executorServiceRef) {
+        setTimeoutExecutorServiceRef(executorServiceRef);
+        return this;
+    }
+
+    /**
      * Configures the thread execution timeout (millis).
      * Default value is 1000 millis (1 second).
      */
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
index 81c1ca9..9292287 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/Resilience4jConfigurationProperties.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.main;
 
+import java.util.concurrent.ForkJoinPool;
+
 /**
  * Global configuration for Resilience EIP circuit breaker.
  */
@@ -38,6 +40,7 @@ public class Resilience4jConfigurationProperties {
     private Integer bulkheadMaxConcurrentCalls;
     private Integer bulkheadMaxWaitDuration;
     private Boolean timeoutEnabled;
+    private String timeoutExecutorServiceRef;
     private Integer timeoutDuration;
     private Boolean timeoutCancelRunningFuture;
 
@@ -256,6 +259,17 @@ public class Resilience4jConfigurationProperties {
         this.timeoutEnabled = timeoutEnabled;
     }
 
+    public String getTimeoutExecutorServiceRef() {
+        return timeoutExecutorServiceRef;
+    }
+
+    /**
+     * References to a custom thread pool to use when timeout is enabled (uses {@link ForkJoinPool#commonPool()} by default)
+     */
+    public void setTimeoutExecutorServiceRef(String timeoutExecutorServiceRef) {
+        this.timeoutExecutorServiceRef = timeoutExecutorServiceRef;
+    }
+
     public Integer getTimeoutDuration() {
         return timeoutDuration;
     }
@@ -437,6 +451,14 @@ public class Resilience4jConfigurationProperties {
     }
 
     /**
+     * References to a custom thread pool to use when timeout is enabled (uses {@link ForkJoinPool#commonPool()} by default)
+     */
+    public Resilience4jConfigurationProperties withTimeoutExecutorServiceRef(String timeoutExecutorServiceRef) {
+        this.timeoutExecutorServiceRef = timeoutExecutorServiceRef;
+        return this;
+    }
+
+    /**
      * Configures the thread execution timeout (millis).
      * Default value is 1000 millis (1 second).
      */
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index 6aac40d..983efdb 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -703,7 +703,7 @@
 			"name":"camel.resilience4j.timeout-duration",
 			"type":"java.lang.Integer",
 			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
-			"description":"Configures the thread execution timeout. Default value is 1 second."
+			"description":"Configures the thread execution timeout (millis). Default value is 1000 millis (1 second)."
 		},
 		{
 			"name":"camel.resilience4j.timeout-enabled",
@@ -712,6 +712,12 @@
 			"description":"Whether timeout is enabled or not on the circuit breaker. Default is false."
 		},
 		{
+			"name":"camel.resilience4j.timeout-executor-service-ref",
+			"type":"java.lang.String",
+			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",
+			"description":"References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool#commonPool() by default)"
+		},
+		{
 			"name":"camel.resilience4j.wait-duration-in-open-state",
 			"type":"java.lang.Integer",
 			"sourceType":"org.apache.camel.main.Resilience4jConfigurationProperties",


[camel] 17/23: CAMEL-13691: camel-resilience4j - WIP

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-13691
in repository https://gitbox.apache.org/repos/asf/camel.git

commit cc808de724c50c43d9d64c4e828e8ea27a91b418
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Nov 18 06:13:45 2019 +0100

    CAMEL-13691: camel-resilience4j - WIP
---
 .../src/main/docs/eips/circuitBreaker-eip.adoc     |  61 +++++++++++++++
 .../src/main/docs/eips/hystrix-eip.adoc            |   2 +-
 .../src/main/docs/eips/resilience4j-eip.adoc       |   2 +-
 .../ROOT/assets/images/eip/CircuitBreaker.png      | Bin 0 -> 24745 bytes
 docs/user-manual/modules/ROOT/nav.adoc             |   2 +-
 .../modules/ROOT/pages/circuitBreaker-eip.adoc     |  82 +++++++++++----------
 .../modules/ROOT/pages/hystrix-eip.adoc            |   6 +-
 .../modules/ROOT/pages/resilience4j-eip.adoc       |  31 +++++---
 8 files changed, 131 insertions(+), 55 deletions(-)

diff --git a/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc b/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc
new file mode 100644
index 0000000..46909dc
--- /dev/null
+++ b/core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc
@@ -0,0 +1,61 @@
+[[circuitBreaker-eip]]
+= CircuitBreaker EIP
+
+The Circuit Breaker pattern is inspired by the real-world electrical circuit breaker,
+which is used to detect excessive current draw and fail fast to protect electrical equipment.
+The software-based circuit breaker works on the same notion, by encapsulating
+the operation and monitoring it for failures. The Circuit Breaker pattern operates in
+three states, as illustrated in the following figure:
+
+image::eip/CircuitBreaker.png[image]
+
+The states are as follows:
+
+* *Closed* — When operating successfully.
+* *Open* — When failure is detected and the breaker opens to short-circuit and fail
+  fast. In this state, the circuit breaker avoids invoking the protected operation and
+  avoids putting additional load on the struggling service.
+* *Half Open* — After a short period in the open state, an operation is attempted to
+  see whether it can complete successfully, and depending on the outcome, it will
+  transfer to either open or closed state.
+
+== Example
+
+Below is an example route showing a circuit breaker endpoint that protects against slow operation by falling back to the in-lined fallback route. By default the timeout request is just *1000ms* so the HTTP endpoint has to be fairly quick to succeed.
+[source,java]
+----
+from("direct:start")
+    .circuitBreaker()
+        .to("http://fooservice.com/slow")
+    .onFallback()
+        .transform().constant("Fallback message")
+    .end()
+    .to("mock:result");
+----
+
+And in XML DSL:
+[source,xml]
+----
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <circuitBreaker>
+      <to uri="http://fooservice.com/slow"/>
+      <onFallback>
+        <transform>
+          <constant>Fallback message</constant>
+        </transform>
+      </onFallback>
+    </circuitBreaker>
+    <to uri="mock:result"/>
+  </route>
+</camelContext>
+----
+
+== CircuitBreaker Implementations
+
+Camel provides two implementations of this pattern:
+
+* xref:hystrix-eip.adoc[Hystrix] - Using the Netflix Hystrix implementation
+* xref:resilience4j-eip.adoc[Resilience4j] - Using the Resilience4j implementation
+
diff --git a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
index 5323d15..2bd2fd5 100644
--- a/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/hystrix-eip.adoc
@@ -111,7 +111,7 @@ You can find an example with the source code: https://github.com/apache/camel/tr
 
 == Using Hystrix with Spring Boot
 
-See the xref:hystrix-component.adoc[Hystrix Component].
+See the xref:components::hystrix.adoc[Hystrix Component].
 
 == Camel's Error Handler and Circuit Breaker EIP
 
diff --git a/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
index 9a0ad62..7f23bda 100644
--- a/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/eips/resilience4j-eip.adoc
@@ -112,7 +112,7 @@ You can find an example with the source code: https://github.com/apache/camel/tr
 
 == Using Resilience4j with Spring Boot
 
-See the xref:components::resilience4j-component.adoc[Resilience4j Component].
+See the xref:components::resilience4j.adoc[Resilience4j Component].
 
 == Camel's Error Handler and Circuit Breaker EIP
 
diff --git a/docs/user-manual/modules/ROOT/assets/images/eip/CircuitBreaker.png b/docs/user-manual/modules/ROOT/assets/images/eip/CircuitBreaker.png
new file mode 100644
index 0000000..5014eb2
Binary files /dev/null and b/docs/user-manual/modules/ROOT/assets/images/eip/CircuitBreaker.png differ
diff --git a/docs/user-manual/modules/ROOT/nav.adoc b/docs/user-manual/modules/ROOT/nav.adoc
index 719f335..1083741 100644
--- a/docs/user-manual/modules/ROOT/nav.adoc
+++ b/docs/user-manual/modules/ROOT/nav.adoc
@@ -65,7 +65,7 @@
  ** xref:batch-config-eip.adoc[Batch-config EIP]
  ** xref:bean-eip.adoc[Bean EIP]
  ** xref:choice-eip.adoc[Choice EIP]
- ** xref:circuitBreaker-eip.adoc[Circuit Breaker EIP (deprecated)]
+ ** xref:circuitBreaker-eip.adoc[CircuitBreaker EIP]
  ** xref:claimCheck-eip.adoc[Claim Check EIP]
  ** xref:content-based-router-eip.adoc[Content Based Router]
  ** xref:content-filter-eip.adoc[Content Filter]
diff --git a/docs/user-manual/modules/ROOT/pages/circuitBreaker-eip.adoc b/docs/user-manual/modules/ROOT/pages/circuitBreaker-eip.adoc
index f68c55d..b3c13e3 100644
--- a/docs/user-manual/modules/ROOT/pages/circuitBreaker-eip.adoc
+++ b/docs/user-manual/modules/ROOT/pages/circuitBreaker-eip.adoc
@@ -1,54 +1,62 @@
 [[circuitBreaker-eip]]
-= Circuit Breaker EIP (deprecated)
+= CircuitBreaker EIP
 :page-source: core/camel-core-engine/src/main/docs/eips/circuitBreaker-eip.adoc
 
-The Circuit Breaker load balancer is a stateful pattern that monitors all calls for certain exceptions. Initially the Circuit Breaker is in closed state and passes all messages. If there are failures and the threshold is reached, it moves to open state and rejects all calls until halfOpenAfter timeout is reached. After this timeout is reached, if there is a new call, it will pass and if the result is success the Circuit Breaker will move to closed state, or to open state if there was an error.
-When the circuit breaker is closed, it will throw a `java.util.concurrent.RejectedExecutionException`. This can then be caught to provide an alternate path for processing exchanges.
+The Circuit Breaker pattern is inspired by the real-world electrical circuit breaker,
+which is used to detect excessive current draw and fail fast to protect electrical equipment.
+The software-based circuit breaker works on the same notion, by encapsulating
+the operation and monitoring it for failures. The Circuit Breaker pattern operates in
+three states, as illustrated in the following figure:
 
-// eip options: START
-The Circuit Breaker EIP supports 3 options which are listed below:
+image::eip/CircuitBreaker.png[image]
 
-[width="100%",cols="2,5,^1,2",options="header"]
-|===
-| Name | Description | Default | Type
-| *exception* | A list of class names for specific exceptions to monitor. If no exceptions is configured then all exceptions is monitored |  | List
-| *halfOpenAfter* | The timeout in millis to use as threshold to move state from closed to half-open or open state |  | Long
-| *threshold* | Number of previous failed messages to use as threshold to move state from closed to half-open or open state |  | Integer
-|===
-// eip options: END
+The states are as follows:
 
+* *Closed* — When operating successfully.
+* *Open* — When failure is detected and the breaker opens to short-circuit and fail
+  fast. In this state, the circuit breaker avoids invoking the protected operation and
+  avoids putting additional load on the struggling service.
+* *Half Open* — After a short period in the open state, an operation is attempted to
+  see whether it can complete successfully, and depending on the outcome, it will
+  transfer to either open or closed state.
 
-An example using Java DSL:
+== Example
+
+Below is an example route showing a circuit breaker endpoint that protects against slow operation by falling back to the in-lined fallback route. By default the timeout request is just *1000ms* so the HTTP endpoint has to be fairly quick to succeed.
 [source,java]
 ----
 from("direct:start")
-    .onException(RejectedExecutionException.class)
-        .handled(true)
-        .to("mock:serviceUnavailable")
+    .circuitBreaker()
+        .to("http://fooservice.com/slow")
+    .onFallback()
+        .transform().constant("Fallback message")
     .end()
-    .loadBalance()
-        .circuitBreaker(2, 1000L, MyCustomException.class)
-        .to("mock:service")
-    .end();
+    .to("mock:result");
 ----
 
-And the same example using Spring XML:
+And in XML DSL:
 [source,xml]
 ----
-<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
-    <route>
-        <from uri="direct:start"/>
-        <onException>
-            <exception>java.util.concurrent.RejectedExecutionException</exception>
-            <handled><constant>true</constant></handled>
-            <to uri="mock:serviceUnavailable"/>
-        </onException>
-        <loadBalance>
-            <circuitBreaker threshold="2" halfOpenAfter="1000">
-                <exception>MyCustomException</exception>
-            </circuitBreaker>
-            <to uri="mock:service"/>
-        </loadBalance>
-    </route>
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <circuitBreaker>
+      <to uri="http://fooservice.com/slow"/>
+      <onFallback>
+        <transform>
+          <constant>Fallback message</constant>
+        </transform>
+      </onFallback>
+    </circuitBreaker>
+    <to uri="mock:result"/>
+  </route>
 </camelContext>
 ----
+
+== CircuitBreaker Implementations
+
+Camel provides two implementations of this pattern:
+
+* xref:hystrix-eip.adoc[Hystrix] - Using the Netflix Hystrix implementation
+* xref:resilience4j-eip.adoc[Resilience4j] - Using the Resilience4j implementation
+
diff --git a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc b/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
index bd98db1..a2c4d62 100644
--- a/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
+++ b/docs/user-manual/modules/ROOT/pages/hystrix-eip.adoc
@@ -11,7 +11,7 @@ Hystrix is one such implementation.
 
 Maven users will need to add the following dependency to their pom.xml to use this EIP:
 
-[source]
+[source,xml]
 ----
 <dependency>
     <groupId>org.apache.camel</groupId>
@@ -28,7 +28,7 @@ The Hystrix EIP supports 2 options which are listed below:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfiguration Definition
+| *hystrixConfiguration* | Configures the Hystrix EIP Use end when configuration is complete, to return back to the Hystrix EIP. |  | HystrixConfigurationDefinition
 | *hystrixConfigurationRef* | Refers to a Hystrix configuration to use for configuring the Hystrix EIP. |  | String
 |===
 // eip options: END
@@ -112,7 +112,7 @@ You can find an example with the source code: https://github.com/apache/camel/tr
 
 == Using Hystrix with Spring Boot
 
-See the xref:hystrix-component.adoc[Hystrix Component].
+See the xref:components::hystrix.adoc[Hystrix Component].
 
 == Camel's Error Handler and Circuit Breaker EIP
 
diff --git a/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc b/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
index 46a6a8c..ad4c07f 100644
--- a/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
+++ b/docs/user-manual/modules/ROOT/pages/resilience4j-eip.adoc
@@ -23,6 +23,14 @@ Maven users will need to add the following dependency to their pom.xml to use th
 == Configuration options
 
 // eip options: START
+The Hystrix EIP supports 2 options which are listed below:
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| *resilienceConfiguration* | Configures the Resilience EIP Use end when configuration is complete, to return back to the Resilience EIP. |  | ResilienceConfigurationDefinition
+| *resilienceConfigurationRef* | Refers to a Resilience configuration to use for configuring the Resilience EIP. |  | String
+|===
 // eip options: END
 
 See xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] for all the configuration options on Resilience Circuit Breaker.
@@ -60,11 +68,10 @@ And in XML DSL:
 </camelContext>
 ----
 
-== Configuring Resilienc4j
+== Configuring Resilience4j
 
 You can fine-tune Resilience4j by the many xref:resilience4jConfiguration-eip.adoc[Resilience4j Configuration] options.
 
-TODO: Update example!!!
 For example to use a 2 second execution timeout, you can do as follows:
 
 [source,java]
@@ -72,12 +79,12 @@ For example to use a 2 second execution timeout, you can do as follows:
 from("direct:start")
     .circuitBreaker()
         // use 2 second timeout
-        .hystrixConfiguration().executionTimeoutInMilliseconds(2000).end()
-        .log("Hystrix processing start: ${threadName}")
+        .resilience4jConfiguration().timeoutEnabled(true).timeoutDuration(2000).end()
+        .log("Resilience processing start: ${threadName}")
         .toD("direct:${body}")
-        .log("Hystrix processing end: ${threadName}")
+        .log("Resilience processing end: ${threadName}")
     .end()
-    .log("After Hystrix ${body}");
+    .log("After Resilience ${body}");
 ----
 
 And in XML:
@@ -87,12 +94,12 @@ And in XML:
 <route>
   <from uri="direct:start"/>
   <circuitBreaker>
-    <hystrixConfiguration executionTimeoutInMilliseconds="2000"/>
-    <log message="Hystrix processing start: ${threadName}"/>
+    <resilience4jConfiguration timeoutEnabled="true" timeoutDuration="2000"/>
+    <log message="Resilience processing start: ${threadName}"/>
     <toD uri="direct:${body}"/>
-    <log message="Hystrix processing end: ${threadName}"/>
+    <log message="Resilience processing end: ${threadName}"/>
   </circuitBreaker>
-  <log message="After Hystrix: ${body}"/>
+  <log message="After Resilience: ${body}"/>
 </route>
 ----
 
@@ -102,11 +109,11 @@ See xref:onFallback-eip.adoc[onFallback].
 
 == Other examples
 
-You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-hystrix[camel-example-hystrix].
+You can find an example with the source code: https://github.com/apache/camel/tree/master/examples/camel-example-resilience4j[camel-example-resilience4j].
 
 == Using Resilience4j with Spring Boot
 
-See the xref:components::resilience4j-component.adoc[Resilience4j Component].
+See the xref:components::resilience4j.adoc[Resilience4j Component].
 
 == Camel's Error Handler and Circuit Breaker EIP