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 <[email protected]>
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",

Reply via email to