This is an automated email from the ASF dual-hosted git repository. nferraro 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 b9c4f01 CAMEL-12555: fix saga behavior when expression evaluation fails b9c4f01 is described below commit b9c4f014b3588c98c369f752bcfd8835ee7063a9 Author: nferraro <ni.ferr...@gmail.com> AuthorDate: Thu Jun 7 16:46:22 2018 +0200 CAMEL-12555: fix saga behavior when expression evaluation fails --- .../camel/impl/saga/InMemorySagaCoordinator.java | 6 +++++- .../camel/processor/saga/RequiredSagaProcessor.java | 4 ++-- .../processor/saga/RequiresNewSagaProcessor.java | 4 ++-- .../apache/camel/processor/saga/SagaProcessor.java | 10 +++++++++- .../org/apache/camel/processor/SagaOptionsTest.java | 19 ++++++++++++++++--- .../apache/camel/service/lra/LRASagaCoordinator.java | 7 ++++++- .../org/apache/camel/service/lra/LRASagaStep.java | 7 ++++++- .../org/apache/camel/service/lra/LRAOptionsIT.java | 11 +++++++++++ 8 files changed, 57 insertions(+), 11 deletions(-) diff --git a/camel-core/src/main/java/org/apache/camel/impl/saga/InMemorySagaCoordinator.java b/camel-core/src/main/java/org/apache/camel/impl/saga/InMemorySagaCoordinator.java index 2fc5c2a..1d3f44e 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/saga/InMemorySagaCoordinator.java +++ b/camel-core/src/main/java/org/apache/camel/impl/saga/InMemorySagaCoordinator.java @@ -84,7 +84,11 @@ public class InMemorySagaCoordinator implements CamelSagaCoordinator { Map<String, Object> values = optionValues.get(step); for (String option : step.getOptions().keySet()) { Expression expression = step.getOptions().get(option); - values.put(option, expression.evaluate(exchange, Object.class)); + try { + values.put(option, expression.evaluate(exchange, Object.class)); + } catch (Exception ex) { + return CompletableFuture.supplyAsync(() -> {throw new RuntimeCamelException("Cannot evaluate saga option '" + option + "'", ex);}); + } } } diff --git a/camel-core/src/main/java/org/apache/camel/processor/saga/RequiredSagaProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/saga/RequiredSagaProcessor.java index 7b77642..ddf4c3b 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/saga/RequiredSagaProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/processor/saga/RequiredSagaProcessor.java @@ -49,9 +49,9 @@ public class RequiredSagaProcessor extends SagaProcessor { inheritedCoordinator = false; } - coordinatorFuture.whenComplete((coordinator, ex2) -> ifNotException(ex2, exchange, callback, () -> { + coordinatorFuture.whenComplete((coordinator, ex2) -> ifNotException(ex2, exchange, !inheritedCoordinator, coordinator, existingCoordinator, callback, () -> { setCurrentSagaCoordinator(exchange, coordinator); - coordinator.beginStep(exchange, step).whenComplete((done, ex3) -> ifNotException(ex3, exchange, callback, () -> { + coordinator.beginStep(exchange, step).whenComplete((done, ex3) -> ifNotException(ex3, exchange, !inheritedCoordinator, coordinator, existingCoordinator, callback, () -> { super.process(exchange, doneSync -> { if (!inheritedCoordinator) { // Saga starts and ends here diff --git a/camel-core/src/main/java/org/apache/camel/processor/saga/RequiresNewSagaProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/saga/RequiresNewSagaProcessor.java index a87fb55..e3d3d96 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/saga/RequiresNewSagaProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/processor/saga/RequiresNewSagaProcessor.java @@ -36,10 +36,10 @@ public class RequiresNewSagaProcessor extends SagaProcessor { @Override public boolean process(Exchange exchange, AsyncCallback callback) { getCurrentSagaCoordinator(exchange).whenComplete((existingCoordinator, ex) -> ifNotException(ex, exchange, callback, () -> - sagaService.newSaga().whenComplete((newCoordinator, ex2) -> ifNotException(ex2, exchange, callback, () -> { + sagaService.newSaga().whenComplete((newCoordinator, ex2) -> ifNotException(ex2, exchange, true, newCoordinator, existingCoordinator, callback, () -> { setCurrentSagaCoordinator(exchange, newCoordinator); - newCoordinator.beginStep(exchange, step).whenComplete((done, ex3) -> ifNotException(ex3, exchange, callback, () -> { + newCoordinator.beginStep(exchange, step).whenComplete((done, ex3) -> ifNotException(ex3, exchange, true, newCoordinator, existingCoordinator, callback, () -> { // Always finalizes the saga super.process(exchange, doneSync -> handleSagaCompletion(exchange, newCoordinator, existingCoordinator, callback)); })); diff --git a/camel-core/src/main/java/org/apache/camel/processor/saga/SagaProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/saga/SagaProcessor.java index ccd239c..95b94f2 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/saga/SagaProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/processor/saga/SagaProcessor.java @@ -98,9 +98,17 @@ public abstract class SagaProcessor extends DelegateAsyncProcessor { } protected void ifNotException(Throwable ex, Exchange exchange, AsyncCallback callback, Runnable code) { + ifNotException(ex, exchange, false, null, null, callback, code); + } + + protected void ifNotException(Throwable ex, Exchange exchange, boolean handleCompletion, CamelSagaCoordinator coordinator, CamelSagaCoordinator previousCoordinator, AsyncCallback callback, Runnable code) { if (ex != null) { exchange.setException(ex); - callback.done(false); + if (handleCompletion) { + handleSagaCompletion(exchange, coordinator, previousCoordinator, callback); + } else { + callback.done(false); + } } else { code.run(); } diff --git a/camel-core/src/test/java/org/apache/camel/processor/SagaOptionsTest.java b/camel-core/src/test/java/org/apache/camel/processor/SagaOptionsTest.java index 0551904..7c88f4c 100644 --- a/camel-core/src/test/java/org/apache/camel/processor/SagaOptionsTest.java +++ b/camel-core/src/test/java/org/apache/camel/processor/SagaOptionsTest.java @@ -18,14 +18,13 @@ package org.apache.camel.processor; import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.impl.saga.InMemorySagaService; -import org.junit.Assert; public class SagaOptionsTest extends ContextTestSupport { - public void testHeaderForwardedToComplete() throws Exception { MockEndpoint complete = getMockEndpoint("mock:complete"); @@ -49,7 +48,7 @@ public class SagaOptionsTest extends ContextTestSupport { try { template.sendBodyAndHeader("direct:workflow", "compensate", "myname", "Nicola"); - Assert.fail("Should throw an exception"); + fail("Should throw an exception"); } catch (Exception ex) { // OK } @@ -57,6 +56,15 @@ public class SagaOptionsTest extends ContextTestSupport { compensate.assertIsSatisfied(); } + public void testRouteDoesNotHangOnOptionError() throws Exception { + try { + template.sendBody("direct:wrong-expression", "Hello"); + fail("Should throw an exception"); + } catch (RuntimeCamelException ex) { + // OK + } + } + @Override protected RouteBuilder createRouteBuilder() throws Exception { @@ -82,6 +90,11 @@ public class SagaOptionsTest extends ContextTestSupport { .setHeader("name", constant("TryToOverride")) .to("mock:endpoint"); + from("direct:wrong-expression") + .saga() + .option("id", simple("${10 / 0}")) + .to("log:info"); + } }; } diff --git a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaCoordinator.java b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaCoordinator.java index 1442454..c870e5e 100644 --- a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaCoordinator.java +++ b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaCoordinator.java @@ -40,7 +40,12 @@ public class LRASagaCoordinator implements CamelSagaCoordinator { @Override public CompletableFuture<Void> beginStep(Exchange exchange, CamelSagaStep step) { - LRASagaStep sagaStep = LRASagaStep.fromCamelSagaStep(step, exchange); + LRASagaStep sagaStep; + try { + sagaStep = LRASagaStep.fromCamelSagaStep(step, exchange); + } catch (RuntimeException ex) { + return CompletableFuture.supplyAsync(() -> {throw ex;}); + } return sagaService.getClient().join(this.lraURL, sagaStep); } diff --git a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaStep.java b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaStep.java index e4b182d..73a43c1 100644 --- a/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaStep.java +++ b/components/camel-lra/src/main/java/org/apache/camel/service/lra/LRASagaStep.java @@ -23,6 +23,7 @@ import java.util.TreeMap; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Expression; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.saga.CamelSagaStep; /** @@ -48,7 +49,11 @@ public final class LRASagaStep { t.timeoutInMilliseconds = step.getTimeoutInMilliseconds(); t.options = new TreeMap<>(); for (Map.Entry<String, Expression> entry : step.getOptions().entrySet()) { - t.options.put(entry.getKey(), entry.getValue().evaluate(exchange, String.class)); + try { + t.options.put(entry.getKey(), entry.getValue().evaluate(exchange, String.class)); + } catch (Exception ex) { + throw new RuntimeCamelException("Cannot evaluate saga option '" + entry.getKey() + "'", ex); + } } return t; } diff --git a/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRAOptionsIT.java b/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRAOptionsIT.java index 72e0a62..f2e4dbf 100644 --- a/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRAOptionsIT.java +++ b/components/camel-lra/src/test/java/org/apache/camel/service/lra/LRAOptionsIT.java @@ -17,6 +17,7 @@ package org.apache.camel.service.lra; import org.apache.camel.Exchange; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.junit.Assert; @@ -57,6 +58,11 @@ public class LRAOptionsIT extends AbstractLRATestSupport { compensate.assertIsSatisfied(); } + @Test(expected = RuntimeCamelException.class) + public void testRouteDoesNotHangOnOptionError() throws Exception { + template.sendBody("direct:wrong-expression", "Hello"); + } + @Override protected RouteBuilder createRouteBuilder() throws Exception { @@ -80,6 +86,11 @@ public class LRAOptionsIT extends AbstractLRATestSupport { .setHeader("name", constant("TryToOverride")) .to("mock:endpoint"); + from("direct:wrong-expression") + .saga() + .option("id", simple("${10 / 0}")) + .to("log:info"); + } }; } -- To stop receiving notification emails like this one, please contact nferr...@apache.org.