CAMEL-11229: Mark exchange as circulr detected for error handler.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/c31f4f2b Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/c31f4f2b Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/c31f4f2b Branch: refs/heads/master Commit: c31f4f2be6ceaca6288a159b9a4da876494b8d9c Parents: 1c6f5cc Author: Claus Ibsen <davscl...@apache.org> Authored: Thu May 11 13:17:14 2017 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu May 11 18:21:08 2017 +0200 ---------------------------------------------------------------------- .../src/main/java/org/apache/camel/Exchange.java | 11 ++++++----- .../processor/FatalFallbackErrorHandler.java | 19 ++++++++++++------- .../onexception/OnExceptionRecursionTest.java | 10 ++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/c31f4f2b/camel-core/src/main/java/org/apache/camel/Exchange.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/Exchange.java b/camel-core/src/main/java/org/apache/camel/Exchange.java index 925e677..eecc7e0 100644 --- a/camel-core/src/main/java/org/apache/camel/Exchange.java +++ b/camel-core/src/main/java/org/apache/camel/Exchange.java @@ -111,11 +111,12 @@ public interface Exchange { String DOCUMENT_BUILDER_FACTORY = "CamelDocumentBuilderFactory"; - String EXCEPTION_CAUGHT = "CamelExceptionCaught"; - String EXCEPTION_HANDLED = "CamelExceptionHandled"; - String EVALUATE_EXPRESSION_RESULT = "CamelEvaluateExpressionResult"; - String ERRORHANDLER_HANDLED = "CamelErrorHandlerHandled"; - String EXTERNAL_REDELIVERED = "CamelExternalRedelivered"; + String EXCEPTION_CAUGHT = "CamelExceptionCaught"; + String EXCEPTION_HANDLED = "CamelExceptionHandled"; + String EVALUATE_EXPRESSION_RESULT = "CamelEvaluateExpressionResult"; + String ERRORHANDLER_CIRCUIT_DETECTED = "CamelFErrorHandlerCircuitDetected"; + String ERRORHANDLER_HANDLED = "CamelErrorHandlerHandled"; + String EXTERNAL_REDELIVERED = "CamelExternalRedelivered"; String FAILURE_HANDLED = "CamelFailureHandled"; String FAILURE_ENDPOINT = "CamelFailureEndpoint"; http://git-wip-us.apache.org/repos/asf/camel/blob/c31f4f2b/camel-core/src/main/java/org/apache/camel/processor/FatalFallbackErrorHandler.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/processor/FatalFallbackErrorHandler.java b/camel-core/src/main/java/org/apache/camel/processor/FatalFallbackErrorHandler.java index b289bb7..9326062 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/FatalFallbackErrorHandler.java +++ b/camel-core/src/main/java/org/apache/camel/processor/FatalFallbackErrorHandler.java @@ -24,6 +24,8 @@ import org.apache.camel.Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.camel.builder.ExpressionBuilder.routeIdExpression; + /** * An {@link org.apache.camel.processor.ErrorHandler} used as a safe fallback when * processing by other error handlers such as the {@link org.apache.camel.model.OnExceptionDefinition}. @@ -52,25 +54,28 @@ public class FatalFallbackErrorHandler extends DelegateAsyncProcessor implements @Override @SuppressWarnings("unchecked") public boolean process(final Exchange exchange, final AsyncCallback callback) { + // get the current route id we use + final String id = routeIdExpression().evaluate(exchange, String.class); + // prevent endless looping if we end up coming back to ourself - Stack<Processor> fatals = exchange.getProperty(Exchange.FATAL_FALLBACK_ERROR_HANDLER, null, Stack.class); + Stack<String> fatals = exchange.getProperty(Exchange.FATAL_FALLBACK_ERROR_HANDLER, null, Stack.class); if (fatals == null) { fatals = new Stack<>(); exchange.setProperty(Exchange.FATAL_FALLBACK_ERROR_HANDLER, fatals); } - if (fatals.search(this) > -1) { - LOG.warn("Circular error-handler detected - breaking out processing Exchange: {}", exchange); + if (fatals.search(id) > -1) { + LOG.warn("Circular error-handler detected at route: {} - breaking out processing Exchange: {}", id, exchange); // mark this exchange as already been error handler handled (just by having this property) // the false value mean the caught exception will be kept on the exchange, causing the // exception to be propagated back to the caller, and to break out routing exchange.setProperty(Exchange.ERRORHANDLER_HANDLED, false); + exchange.setProperty(Exchange.ERRORHANDLER_CIRCUIT_DETECTED, true); callback.done(true); return true; } // okay we run under this fatal error handler now - final Processor fatal = this; - fatals.push(fatal); + fatals.push(id); // support the asynchronous routing engine boolean sync = processor.process(exchange, new AsyncCallback() { @@ -137,9 +142,9 @@ public class FatalFallbackErrorHandler extends DelegateAsyncProcessor implements } } finally { // no longer running under this fatal fallback error handler - Stack<Processor> fatals = exchange.getProperty(Exchange.FATAL_FALLBACK_ERROR_HANDLER, null, Stack.class); + Stack<String> fatals = exchange.getProperty(Exchange.FATAL_FALLBACK_ERROR_HANDLER, null, Stack.class); if (fatals != null) { - fatals.remove(fatal); + fatals.remove(id); } callback.done(doneSync); } http://git-wip-us.apache.org/repos/asf/camel/blob/c31f4f2b/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRecursionTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRecursionTest.java b/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRecursionTest.java index bd12b0d..bac6e40 100644 --- a/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRecursionTest.java +++ b/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRecursionTest.java @@ -53,8 +53,9 @@ public class OnExceptionRecursionTest extends ContextTestSupport { getMockEndpoint("mock:a").expectedMessageCount(1); getMockEndpoint("mock:b").expectedMessageCount(0); - getMockEndpoint("mock:c").expectedMessageCount(1); - getMockEndpoint("mock:d").expectedMessageCount(1); + // will be called twice because of the two exceptions because the circular exception is detected to break out + getMockEndpoint("mock:c").expectedMessageCount(2); + getMockEndpoint("mock:d").expectedMessageCount(2); try { template.sendBody("direct:test", "Hello World"); @@ -67,8 +68,7 @@ public class OnExceptionRecursionTest extends ContextTestSupport { assertEquals("Bad state", ise.getMessage()); } - // TODO: should only trigger error handling in direct route one time - // assertMockEndpointsSatisfied(); + assertMockEndpointsSatisfied(); } public void testRecursionDirectNoErrorHandler() throws Exception { @@ -94,6 +94,8 @@ public class OnExceptionRecursionTest extends ContextTestSupport { getMockEndpoint("mock:a").expectedMessageCount(1); getMockEndpoint("mock:b").expectedMessageCount(0); + // we will only be called once because when the route fails its not under error handler + // and therefore onException wont trigger the 2nd time getMockEndpoint("mock:c").expectedMessageCount(1); getMockEndpoint("mock:d").expectedMessageCount(1);