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 2018/08/05 07:39:37 UTC

[camel] branch master updated: CAMEL-12699: Allow hystrix EIP to inherit error handler so you can combine Camels error handler for redeliveries with the circuit breaker.

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 33bae98  CAMEL-12699: Allow hystrix EIP to inherit error handler so you can combine Camels error handler for redeliveries with the circuit breaker.
33bae98 is described below

commit 33bae980841bd5bf22dcd525a3c530df1571f588
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Aug 5 08:39:23 2018 +0200

    CAMEL-12699: Allow hystrix EIP to inherit error handler so you can combine Camels error handler for redeliveries with the circuit breaker.
---
 camel-core/src/main/docs/eips/hystrix-eip.adoc     | 33 +++++++++++++
 .../apache/camel/model/ProcessorDefinition.java    | 10 +++-
 .../camel-hystrix/src/main/docs/hystrix.adoc       |  4 +-
 .../processor/HystrixInheritErrorHandlerTest.java  | 56 ++++++++++++++++++++++
 4 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/camel-core/src/main/docs/eips/hystrix-eip.adoc b/camel-core/src/main/docs/eips/hystrix-eip.adoc
index 1dae7a3..bb6701b 100644
--- a/camel-core/src/main/docs/eips/hystrix-eip.adoc
+++ b/camel-core/src/main/docs/eips/hystrix-eip.adoc
@@ -29,6 +29,39 @@ The Hystrix EIP supports 2 options which are listed below:
 |===
 // eip options: END
 
+=== Camel's Error Handler and Hystrix EIP
+
+By default the Hystrix 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 from *Camel 2.23* onwards
+you can enable Camels error handler with Hystrix by enabling the `inheritErrorHandler` option, as shown:
+
+[source,java]
+----
+// Camel's error handler that will attempt to redeliver the message 3 times
+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
+    .hystrix().inheritErrorHandler(true)
+        .to("mock:a")
+        .throwException(new IllegalArgumentException("Forced"))
+    .end()
+    .to("log:result")
+    .to("mock:result");
+----
+
+This example is from an unit test, where you can see the Hystrix EIP block has been hardcoded
+to always fail by throwning an exception. Because the `inheritErrorHandler` has been enabled,
+then Camel's error handler will attempt to call the Hystrix 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
+executed once because it handled the error itself.
+
+
 === 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.
diff --git a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 9108d78..535a678 100644
--- a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -312,8 +312,14 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
             log.trace("{} is part of OnException so no error handler is applied", defn);
             // do not use error handler for onExceptions blocks as it will handle errors itself
         } else if (defn instanceof HystrixDefinition || ProcessorDefinitionHelper.isParentOfType(HystrixDefinition.class, defn, true)) {
-            log.trace("{} is part of HystrixCircuitBreaker so no error handler is applied", defn);
-            // do not use error handler for hystrixCircuitBreaker blocks as it will handle errors itself
+            // do not use error handler for hystrix as it offers circuit breaking with fallback for its outputs
+            // however if inherit error handler is enabled, we need to wrap an error handler on the hystrix parent
+            if (inheritErrorHandler != null && inheritErrorHandler && child == null) {
+                // only wrap the parent (not the children of the hystrix)
+                wrapChannelInErrorHandler(channel, routeContext, inheritErrorHandler);
+            } else {
+                log.trace("{} is part of HystrixCircuitBreaker so no error handler is applied", defn);
+            }
         } else if (defn instanceof MulticastDefinition) {
             // do not use error handler for multicast as it offers fine grained error handlers for its outputs
             // however if share unit of work is enabled, we need to wrap an error handler on the multicast parent
diff --git a/components/camel-hystrix/src/main/docs/hystrix.adoc b/components/camel-hystrix/src/main/docs/hystrix.adoc
index 3b9a191..c8d8f3b 100644
--- a/components/camel-hystrix/src/main/docs/hystrix.adoc
+++ b/components/camel-hystrix/src/main/docs/hystrix.adoc
@@ -1,9 +1,11 @@
-## Hystrix Component
+== Hystrix Component
 
 *Available as of Camel version 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:
 
diff --git a/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixInheritErrorHandlerTest.java b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixInheritErrorHandlerTest.java
new file mode 100644
index 0000000..b6db3f3
--- /dev/null
+++ b/components/camel-hystrix/src/test/java/org/apache/camel/component/hystrix/processor/HystrixInheritErrorHandlerTest.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.hystrix.processor;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+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
+                    .hystrix().inheritErrorHandler(true)
+                        .to("mock:a")
+                        .throwException(new IllegalArgumentException("Forced"))
+                    .end()
+                    .to("log:result")
+                    .to("mock:result");
+            }
+        };
+    }
+
+}