How Apache camel error handling works with multicast and transactions

Viewed 1566

I got spring boot (2.3.2.RELEASE) with camel (3.5.0) application and two routes for testing in it:

The idea is to check what happen when exception occurred in child route that was called from multicast and how it work with transactions.

@Component
public class MyRoute1 extends RouteBuilder {

@Override
public void configure() {

    onException(Exception.class)
        .useOriginalBody()
        .log("Error handler parent. Body is: ${body}")
        .process(new Processor() {
            @Override
            public void process(Exchange exchange) throws Exception {
                Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
                System.out.println(cause.getMessage());
                cause.printStackTrace(System.out);
            }
        })
        .handled(true);

    from("jms:queue:EventsQueue")
        .routeId("route1")
        .onCompletion().log("On complete parent").end()
        .transacted()
        .multicast(AggregationStrategies.useOriginal(), false)
            .to("direct:route2")
            .log("Second step")
        .end()
        .log("Third step");

}
}

And

@Component
public class MyRoute2 extends RouteBuilder {

@Override
public void configure() {

    onException(IOException.class)
        .log("Error handling child");

    from("direct:route2")
        .routeId("route2")
        .onCompletion().log("On complete child").end()
        .log("First step")
        .throwException(new IOException("Very bad exception"));

}

}

When I send message into jms:queue:EventsQueue I expect that exchange will failed with my exception thrown and following order of custom log messages:

First step
Error handling child
On complete child
On complete parent

Other log messages should not be triggered.

But I have the following behavior: java.lang.NullPointerException was thrown by multicast aggregation strategy and caught in parent onException block. So the order of custom logs is:

First step
Error handling child
On complete child
Error handler parent
null
java.lang.NullPointerException
    at org.apache.camel.processor.aggregate.UseOriginalAggregationStrategy.aggregate(UseOriginalAggregationStrategy.java:62)
...
On complete parent

Interesting part comes here: If i remove .transacted() method in parent route behavior changes. The java.lang.NullPointerException exception is still throwing by aggregation strategy, but it does not caught in my parents onException block.

Camel logs with .transacted():

2020-11-03 14:38:35.800  INFO 11744 --- [           main] a.test.errors.MySpringBootApplication    : Started MySpringBootApplication in 3.44 seconds (JVM running for 3.916)
2020-11-03 14:38:46.389  INFO 11744 --- [[EventsPsQueue]] route2                                   : First step
2020-11-03 14:38:46.394  INFO 11744 --- [[EventsPsQueue]] route2                                   : Error handling child
2020-11-03 14:38:46.398 ERROR 11744 --- [[EventsPsQueue]] o.a.c.p.e.DefaultErrorHandler            : Failed delivery for (MessageId: queue_EventsPsQueue_ID_wsc-111-71a-44245-1603872340334-4_9_1_1_3 on ExchangeId: ID-wsc-111-71a-1604403526383-0-2). Exhausted after delivery attempt: 1 caught: java.io.IOException: Very bad exception. Processed by failure processor: FatalFallbackErrorHandler[Channel[log5]]

Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [from[jms://queue:EventsPsQueue]                                               ] [        25]

Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------


java.io.IOException: Very bad exception
    at activemq.test.errors.chapter1.MyRoute2.configure(MyRoute2.java:20) ~[classes/:na]
    at org.apache.camel.builder.RouteBuilder.checkInitialized(RouteBuilder.java:483) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.builder.RouteBuilder.configureRoutes(RouteBuilder.java:430) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.builder.RouteBuilder.addRoutesToCamelContext(RouteBuilder.java:405) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.AbstractCamelContext.addRoutes(AbstractCamelContext.java:1185) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.main.RoutesConfigurer.configureRoutes(RoutesConfigurer.java:93) ~[camel-main-3.5.0.jar:3.5.0]
    at org.apache.camel.spring.boot.CamelSpringBootApplicationListener.onApplicationEvent(CamelSpringBootApplicationListener.java:101) ~[camel-spring-boot-3.5.0.jar:3.5.0]
    at org.apache.camel.spring.boot.CamelSpringBootApplicationListener.onApplicationEvent(CamelSpringBootApplicationListener.java:57) ~[camel-spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at activemq.test.errors.MySpringBootApplication.main(MySpringBootApplication.java:13) ~[classes/:na]

2020-11-03 14:38:46.400  WARN 11744 --- [[EventsPsQueue]] o.a.c.s.spi.TransactionErrorHandler      : Transaction rollback (0x347b370c) redelivered(false) for (MessageId: queue_EventsPsQueue_ID_wsc-111-71a-44245-1603872340334-4_9_1_1_3 on ExchangeId: ID-wsc-111-71a-1604403526383-0-2) caught: java.io.IOException: Very bad exception
2020-11-03 14:38:46.401  INFO 11744 --- [[EventsPsQueue]] route2                                   : On completion child
2020-11-03 14:38:46.401  INFO 11744 --- [[EventsPsQueue]] route1                                   : Error handler parent. Body is: TEST MESSAGE
null
java.lang.NullPointerException
    at org.apache.camel.processor.aggregate.UseOriginalAggregationStrategy.aggregate(UseOriginalAggregationStrategy.java:62)
    at org.apache.camel.AggregationStrategy.aggregate(AggregationStrategy.java:86)
    at org.apache.camel.processor.MulticastProcessor.doAggregateInternal(MulticastProcessor.java:628)
    at org.apache.camel.processor.MulticastProcessor.doAggregateSync(MulticastProcessor.java:609)
    at org.apache.camel.processor.MulticastProcessor.doAggregate(MulticastProcessor.java:594)
    at org.apache.camel.processor.MulticastProcessor$MulticastTask.aggregate(MulticastProcessor.java:413)
    at org.apache.camel.processor.MulticastProcessor$MulticastTask.lambda$null$0(MulticastProcessor.java:393)
    at org.apache.camel.AsyncCallback.run(AsyncCallback.java:44)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.schedule(DefaultReactiveExecutor.java:55)
    at org.apache.camel.processor.CamelInternalProcessor$AsyncAfterTask.done(CamelInternalProcessor.java:186)
    at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:129)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287)
    at org.apache.camel.processor.MulticastProcessor$MulticastTask.lambda$run$1(MulticastProcessor.java:367)
    at org.apache.camel.util.concurrent.AsyncCompletionService$Task.run(AsyncCompletionService.java:150)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:65)
    at org.apache.camel.processor.MulticastProcessor.process(MulticastProcessor.java:273)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:723)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:632)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:65)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:181)
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:164)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:261)
    at org.apache.camel.processor.Pipeline$PipelineTask.run(Pipeline.java:90)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:65)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:145)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:723)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:632)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:65)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:181)
    at org.apache.camel.spring.spi.TransactionErrorHandler.access$201(TransactionErrorHandler.java:45)
    at org.apache.camel.spring.spi.TransactionErrorHandler$2.process(TransactionErrorHandler.java:238)
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
    at org.apache.camel.spring.spi.TransactionErrorHandler.processByErrorHandler(TransactionErrorHandler.java:235)
    at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:110)
    at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:123)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.doRun(RedeliveryErrorHandler.java:723)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$RedeliveryTask.run(RedeliveryErrorHandler.java:632)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:65)
    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:181)
    at org.apache.camel.spring.spi.TransactionErrorHandler.access$201(TransactionErrorHandler.java:45)
    at org.apache.camel.spring.spi.TransactionErrorHandler$2.process(TransactionErrorHandler.java:238)
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
    at org.apache.camel.spring.spi.TransactionErrorHandler.processByErrorHandler(TransactionErrorHandler.java:235)
    at org.apache.camel.spring.spi.TransactionErrorHandler$1.doInTransactionWithoutResult(TransactionErrorHandler.java:198)
    at org.springframework.transaction.support.TransactionCallbackWithoutResult.doInTransaction(TransactionCallbackWithoutResult.java:36)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
    at org.apache.camel.spring.spi.TransactionErrorHandler.doInTransactionTemplate(TransactionErrorHandler.java:191)
    at org.apache.camel.spring.spi.TransactionErrorHandler.processInTransaction(TransactionErrorHandler.java:146)
    at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:114)
    at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:123)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287)
    at org.apache.camel.processor.Pipeline$PipelineTask.run(Pipeline.java:90)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:147)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287)
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
    at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41)
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:130)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696)
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318)
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:245)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179)
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
2020-11-03 14:38:46.407  INFO 11744 --- [[EventsPsQueue]] route1                                   : On complete parent
2020-11-03 14:38:46.411  WARN 11744 --- [[EventsPsQueue]] c.c.j.DefaultJmsMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'EventsPsQueue' - trying to recover. Cause: Transaction rolled back because it has been marked as rollback-only

Camel logs without transaction support:

2020-11-03 14:40:27.748  INFO 11981 --- [           main] a.test.errors.MySpringBootApplication    : Started MySpringBootApplication in 3.234 seconds (JVM running for 3.643)
2020-11-03 14:40:36.828  INFO 11981 --- [[EventsPsQueue]] route2                                   : First step
2020-11-03 14:40:36.832  INFO 11981 --- [[EventsPsQueue]] route2                                   : Error handling child
2020-11-03 14:40:36.837 ERROR 11981 --- [[EventsPsQueue]] o.a.c.p.e.DefaultErrorHandler            : Failed delivery for (MessageId: queue_EventsPsQueue_ID_wsc-111-71a-44245-1603872340334-4_9_1_1_4 on ExchangeId: ID-wsc-111-71a-1604403636824-0-2). Exhausted after delivery attempt: 1 caught: java.io.IOException: Very bad exception. Processed by failure processor: FatalFallbackErrorHandler[Channel[log5]]

Message History (complete message history is disabled)
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [from[jms://queue:EventsPsQueue]                                               ] [        24]

Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------


java.io.IOException: Very bad exception
    at activemq.test.errors.chapter1.MyRoute2.configure(MyRoute2.java:20) ~[classes/:na]
    at org.apache.camel.builder.RouteBuilder.checkInitialized(RouteBuilder.java:483) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.builder.RouteBuilder.configureRoutes(RouteBuilder.java:430) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.builder.RouteBuilder.addRoutesToCamelContext(RouteBuilder.java:405) ~[camel-core-engine-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.AbstractCamelContext.addRoutes(AbstractCamelContext.java:1185) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.main.RoutesConfigurer.configureRoutes(RoutesConfigurer.java:93) ~[camel-main-3.5.0.jar:3.5.0]
    at org.apache.camel.spring.boot.CamelSpringBootApplicationListener.onApplicationEvent(CamelSpringBootApplicationListener.java:101) ~[camel-spring-boot-3.5.0.jar:3.5.0]
    at org.apache.camel.spring.boot.CamelSpringBootApplicationListener.onApplicationEvent(CamelSpringBootApplicationListener.java:57) ~[camel-spring-boot-3.5.0.jar:3.5.0]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.2.RELEASE.jar:2.3.2.RELEASE]
    at activemq.test.errors.MySpringBootApplication.main(MySpringBootApplication.java:13) ~[classes/:na]

2020-11-03 14:40:36.838  INFO 11981 --- [[EventsPsQueue]] route2                                   : On completion child
2020-11-03 14:40:36.839  INFO 11981 --- [[EventsPsQueue]] route1                                   : On complete parent
2020-11-03 14:40:36.848  WARN 11981 --- [[EventsPsQueue]] o.a.c.c.jms.EndpointMessageListener      : Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - java.lang.NullPointerException]

org.apache.camel.RuntimeCamelException: java.lang.NullPointerException
    at org.apache.camel.RuntimeCamelException.wrapRuntimeCamelException(RuntimeCamelException.java:51) ~[camel-api-3.5.0.jar:3.5.0]
    at org.apache.camel.component.jms.EndpointMessageListener$EndpointMessageListenerAsyncCallback.done(EndpointMessageListener.java:213) ~[camel-jms-3.5.0.jar:3.5.0]
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:134) ~[camel-jms-3.5.0.jar:3.5.0]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:245) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076) ~[spring-jms-5.2.8.RELEASE.jar:5.2.8.RELEASE]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: java.lang.NullPointerException: null
    at org.apache.camel.processor.aggregate.UseOriginalAggregationStrategy.aggregate(UseOriginalAggregationStrategy.java:62) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.AggregationStrategy.aggregate(AggregationStrategy.java:86) ~[camel-api-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.MulticastProcessor.doAggregateInternal(MulticastProcessor.java:628) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.MulticastProcessor.doAggregateSync(MulticastProcessor.java:609) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.MulticastProcessor.doAggregate(MulticastProcessor.java:594) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.MulticastProcessor$MulticastTask.aggregate(MulticastProcessor.java:413) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.MulticastProcessor$MulticastTask.lambda$null$0(MulticastProcessor.java:393) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.AsyncCallback.run(AsyncCallback.java:44) ~[camel-api-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:60) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:147) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:287) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83) ~[camel-base-3.5.0.jar:3.5.0]
    at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41) ~[camel-support-3.5.0.jar:3.5.0]
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:130) ~[camel-jms-3.5.0.jar:3.5.0]
    ... 11 common frames omitted

The questions are:

  • Why do I have java.lang.NullPointerException during multicast if other exception occurred in child route.
  • Why do I have different error handling behavior with transaction support and without it.

I will be glad for any help or advice!

2 Answers

For onException there are two other thing you can set to be true or false which are handled and continued. I think those explain to you how the exception propagates to parent route.

If handled is true, then the thrown exception will be handled and Camel will not continue routing in the original route, but break out

https://camel.apache.org/manual/latest/exception-clause.html#ExceptionClause-WhatistheDifferenceBetweenHandledandContinued

In Camel 2.3 we introduced a new option continued which allows you to both handle and continue routing in the original route as if the exception did not occur.

https://camel.apache.org/manual/latest/exception-clause.html#ExceptionClause-HandleandContinueExceptions

About that transacted() I don't know. I am reading about it and if I find the answer will link you to that.

This is the expected behavior.

Let me first quote from the official Camel documentation.

  • Difference between non transactional and transactional error handling.

Error handling in Camel can roughly be separated into two distinct types:

  • non transactional
  • transactional

Where non transactional is the most common type that is enabled out-of-the-box and handled by Camel itself. The transaction type is handled by a backing system such as a J2EE application server.

  • Then, this is how Camel handles errors by default.

In Camel 2.0 onwards a global DefaultErrorHandler is set up as the Error Handler by default. It's configured as:

  • no redeliveries
  • no dead letter queue

If the exchange failed an exception is thrown and propagated back to the original caller wrapped in a RuntimeCamelException.

  • Finally, this is how the multicast EIP changes this behavior.

The multicast EIP will by default continue to process the entire exchange even in case one of the multicasted messages will throw an exception during routing.

When the exception is thrown in your non-transactional route, only the DefaultErrorHandler kicks in logging an error, but the route execution continues as we are inside the multicast EIP. The route completes and no exception is propagated back.

When the exception is thrown in your transactional route, the TransactionErrorHandler also kicks in and stops the route execution to trigger a rollback in the backing system. At this point, the exception is wrapped and propagated back by Camel, where your onException logic is called.

Related