Search code examples
exceptionmuleesbrollback

Why does a mule rollback exception propagate to the flow that called it?


I have a mule project where a flow with a rollback exception is causing an exception to be thrown in the flow that references it. Is this normal behaviour?

Here is the code:

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:file="http://www.mulesoft.org/schema/mule/file"xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.5.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core     http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd">
<file:connector name="File"  autoDelete="true" streaming="false" validateConnections="true" doc:name="File"/>
<flow name="rollbacktestFlow2" doc:name="rollbacktestFlow2">
    <file:inbound-endpoint path="C:\RollbackTEst\In" responseTimeout="10000" doc:name="File" connector-ref="File"/>
    <logger message="File Rx" level="INFO" doc:name="FileRx"/>
    <flow-ref name="rollbacktestFlow1" doc:name="Flow Reference"/>
    <catch-exception-strategy doc:name="Catch Exception Strategy">
        <logger message="Rollbacktestflow 2" level="INFO" doc:name="Rollbacktestflow2"/>
    </catch-exception-strategy>
</flow>
<flow name="rollbacktestFlow1" doc:name="rollbacktestFlow1" >
    <logger message="Rollback trigger" level="INFO" doc:name="RollbackTrigger"/>
    <expression-component doc:name="Expression"><![CDATA[forceException]]></expression-component>
    <rollback-exception-strategy maxRedeliveryAttempts="4" doc:name="Rollback Exception Strategy">
        <logger message="retry" level="INFO" doc:name="retry"/>
        <expression-component doc:name="Copy_of_Expression"><![CDATA[forceException]]></expression-component>
        <on-redelivery-attempts-exceeded doc:name="Redelivery exhausted">
            <logger message="exhausted" level="INFO" doc:name="exhausted"/>
        </on-redelivery-attempts-exceeded>
    </rollback-exception-strategy>
</flow>

Should the rollback section of the exception not be executed 4 times and then the redelivery exhausted exception be thrown?

Here is the log:

    INFO  2014-11-12 15:36:40,529 [main] org.mule.module.launcher.MuleDeploymentService: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Started app 'rollbacktest'                               +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2014-11-12 15:36:40,544 [main] org.mule.module.launcher.DeploymentDirectoryWatcher: 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ Mule is up and kicking (every 5000ms)                    +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
INFO  2014-11-12 15:37:18,031 [[rollbacktest].File.receiver.01] org.mule.transport.file.FileMessageReceiver: Lock obtained on file: C:\RollbackTEst\In\New Text Document.txt
INFO  2014-11-12 15:37:18,048 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.api.processor.LoggerMessageProcessor: File Rx
INFO  2014-11-12 15:37:18,048 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.api.processor.LoggerMessageProcessor: Rollback trigger
ERROR 2014-11-12 15:37:18,079 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.exception.RollbackMessagingExceptionStrategy: 
********************************************************************************
Message               : Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[]
Code                  : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. [Error: unresolvable property or identifier: forceException]
[Near : {... forceException ....}]
             ^
[Line: 1, Column: 1] (org.mule.mvel2.PropertyAccessException)
  org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer:692 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/mvel2/PropertyAccessException.html)
2. Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException)
  org.mule.el.mvel.MVELExpressionLanguage:202 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/expression/ExpressionRuntimeException.html)
3. Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[] (org.mule.api.MessagingException)
  org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:32 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
[Error: unresolvable property or identifier: forceException]
[Near : {... forceException ....}]
             ^
[Line: 1, Column: 1]
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getBeanProperty(ReflectiveAccessorOptimizer.java:692)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(ReflectiveAccessorOptimizer.java:337)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(ReflectiveAccessorOptimizer.java:140)
    + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

INFO  2014-11-12 15:37:18,079 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.api.processor.LoggerMessageProcessor: retry
ERROR 2014-11-12 15:37:18,079 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.exception.RollbackMessagingExceptionStrategy: Failed to dispatch message to error queue after it failed to process.  This may cause message loss.Logging Message here: 

org.mule.DefaultMuleMessage
{
  id=c8cf45f1-6a81-11e4-887d-005056b6086b
  payload=[B
  correlationId=<not set>
  correlationGroup=-1
  correlationSeq=-1
  encoding=UTF-8
  exceptionPayload=org.mule.message.DefaultExceptionPayload@1975a694

Message properties:
  INVOCATION scoped properties:
    originalFilename=New Text Document.txt
  INBOUND scoped properties:
    MULE_ORIGINATING_ENDPOINT=endpoint..C.Users.mik119.Desktop.RollbackTEst.In
    directory=C:\RollbackTEst\In
    fileSize=0
    originalFilename=New Text Document.txt
    timestamp=1415806637595
  OUTBOUND scoped properties:
    MULE_ENCODING=UTF-8
  SESSION scoped properties:
}
org.mule.api.MessagingException: Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[]
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:32)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:58)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.chain.DefaultMessageProcessorChain.doProcess(DefaultMessageProcessorChain.java:94)
    at org.mule.processor.chain.AbstractMessageProcessorChain.process(AbstractMessageProcessorChain.java:67)
    at org.mule.processor.chain.InterceptingChainLifecycleWrapper.doProcess(InterceptingChainLifecycleWrapper.java:50)
    at org.mule.processor.chain.AbstractMessageProcessorChain.process(AbstractMessageProcessorChain.java:67)
    at org.mule.processor.chain.InterceptingChainLifecycleWrapper.access$001(InterceptingChainLifecycleWrapper.java:22)
    at org.mule.processor.chain.InterceptingChainLifecycleWrapper$1.process(InterceptingChainLifecycleWrapper.java:66)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:58)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.chain.InterceptingChainLifecycleWrapper.process(InterceptingChainLifecycleWrapper.java:61)
    at org.mule.exception.TemplateMessagingExceptionStrategy.route(TemplateMessagingExceptionStrategy.java:139)
    at org.mule.exception.RollbackMessagingExceptionStrategy.route(RollbackMessagingExceptionStrategy.java:104)
    at org.mule.exception.TemplateMessagingExceptionStrategy.handleException(TemplateMessagingExceptionStrategy.java:45)
    at org.mule.execution.HandleExceptionInterceptor.execute(HandleExceptionInterceptor.java:37)
    at org.mule.execution.HandleExceptionInterceptor.execute(HandleExceptionInterceptor.java:14)
    at org.mule.execution.BeginAndResolveTransactionInterceptor.execute(BeginAndResolveTransactionInterceptor.java:54)
    at org.mule.execution.SuspendXaTransactionInterceptor.execute(SuspendXaTransactionInterceptor.java:50)
    at org.mule.execution.RethrowExceptionInterceptor.execute(RethrowExceptionInterceptor.java:28)
    at org.mule.execution.RethrowExceptionInterceptor.execute(RethrowExceptionInterceptor.java:13)
    at org.mule.execution.ErrorHandlingExecutionTemplate.execute(ErrorHandlingExecutionTemplate.java:59)
    at org.mule.execution.ErrorHandlingExecutionTemplate.execute(ErrorHandlingExecutionTemplate.java:30)
    at org.mule.construct.Flow.process(Flow.java:76)
    at org.mule.config.spring.factories.FlowRefFactoryBean$2.process(FlowRefFactoryBean.java:145)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:58)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.chain.DefaultMessageProcessorChain.doProcess(DefaultMessageProcessorChain.java:94)
    at org.mule.processor.chain.AbstractMessageProcessorChain.process(AbstractMessageProcessorChain.java:67)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
    at org.mule.processor.AbstractInterceptingMessageProcessorBase.processNext(AbstractInterceptingMessageProcessorBase.java:102)
    at org.mule.interceptor.AbstractEnvelopeInterceptor.process(AbstractEnvelopeInterceptor.java:51)
    at org.mule.processor.AsyncInterceptingMessageProcessor.processNextTimed(AsyncInterceptingMessageProcessor.java:118)
    at org.mule.processor.AsyncInterceptingMessageProcessor$AsyncMessageProcessorWorker$1.process(AsyncInterceptingMessageProcessor.java:189)
    at org.mule.processor.AsyncInterceptingMessageProcessor$AsyncMessageProcessorWorker$1.process(AsyncInterceptingMessageProcessor.java:182)
    at org.mule.execution.ExecuteCallbackInterceptor.execute(ExecuteCallbackInterceptor.java:16)
    at org.mule.execution.HandleExceptionInterceptor.execute(HandleExceptionInterceptor.java:30)
    at org.mule.execution.HandleExceptionInterceptor.execute(HandleExceptionInterceptor.java:14)
    at org.mule.execution.BeginAndResolveTransactionInterceptor.execute(BeginAndResolveTransactionInterceptor.java:54)
    at org.mule.execution.ResolvePreviousTransactionInterceptor.execute(ResolvePreviousTransactionInterceptor.java:44)
    at org.mule.execution.SuspendXaTransactionInterceptor.execute(SuspendXaTransactionInterceptor.java:50)
    at org.mule.execution.ValidateTransactionalStateInterceptor.execute(ValidateTransactionalStateInterceptor.java:40)
    at org.mule.execution.IsolateCurrentTransactionInterceptor.execute(IsolateCurrentTransactionInterceptor.java:41)
    at org.mule.execution.ExternalTransactionInterceptor.execute(ExternalTransactionInterceptor.java:48)
    at org.mule.execution.RethrowExceptionInterceptor.execute(RethrowExceptionInterceptor.java:28)
    at org.mule.execution.RethrowExceptionInterceptor.execute(RethrowExceptionInterceptor.java:13)
    at org.mule.execution.TransactionalErrorHandlingExecutionTemplate.execute(TransactionalErrorHandlingExecutionTemplate.java:109)
    at org.mule.execution.TransactionalErrorHandlingExecutionTemplate.execute(TransactionalErrorHandlingExecutionTemplate.java:30)
    at org.mule.processor.AsyncInterceptingMessageProcessor$AsyncMessageProcessorWorker.doRun(AsyncInterceptingMessageProcessor.java:181)
    at org.mule.work.AbstractMuleEventWork.run(AbstractMuleEventWork.java:39)
    at org.mule.work.WorkerContext.run(WorkerContext.java:286)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.mule.api.expression.ExpressionRuntimeException: Execution of the expression "forceException" failed.
    at org.mule.el.mvel.MVELExpressionLanguage.evaluateInternal(MVELExpressionLanguage.java:202)
    at org.mule.el.mvel.MVELExpressionLanguage.evaluate(MVELExpressionLanguage.java:154)
    at org.mule.el.mvel.MVELExpressionLanguage.evaluate(MVELExpressionLanguage.java:133)
    at org.mule.el.ExpressionLanguageComponent.process(ExpressionLanguageComponent.java:51)
    at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
    ... 56 more
Caused by: [Error: unresolvable property or identifier: forceException]
[Near : {... forceException ....}]
             ^
[Line: 1, Column: 1]
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getBeanProperty(ReflectiveAccessorOptimizer.java:692)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(ReflectiveAccessorOptimizer.java:337)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(ReflectiveAccessorOptimizer.java:140)
    at org.mule.mvel2.ast.ASTNode.optimize(ASTNode.java:159)
    at org.mule.mvel2.ast.ASTNode.getReducedValueAccelerated(ASTNode.java:115)
    at org.mule.mvel2.MVELRuntime.execute(MVELRuntime.java:86)
    at org.mule.mvel2.compiler.CompiledExpression.getDirectValue(CompiledExpression.java:123)
    at org.mule.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:119)
    at org.mule.mvel2.MVEL.executeExpression(MVEL.java:943)
    at org.mule.el.mvel.MVELExpressionExecutor.execute(MVELExpressionExecutor.java:72)
    at org.mule.el.mvel.MVELExpressionLanguage.evaluateInternal(MVELExpressionLanguage.java:198)
    ... 60 more
ERROR 2014-11-12 15:37:18,095 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.exception.CatchMessagingExceptionStrategy: 
********************************************************************************
Message               : Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[]
Code                  : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. [Error: unresolvable property or identifier: forceException]
[Near : {... forceException ....}]
             ^
[Line: 1, Column: 1] (org.mule.mvel2.PropertyAccessException)
  org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer:692 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/mvel2/PropertyAccessException.html)
2. Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException)
  org.mule.el.mvel.MVELExpressionLanguage:202 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/expression/ExpressionRuntimeException.html)
3. Execution of the expression "forceException" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: byte[] (org.mule.api.MessagingException)
  org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:32 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
[Error: unresolvable property or identifier: forceException]
[Near : {... forceException ....}]
             ^
[Line: 1, Column: 1]
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.getBeanProperty(ReflectiveAccessorOptimizer.java:692)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.compileGetChain(ReflectiveAccessorOptimizer.java:337)
    at org.mule.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer.optimizeAccessor(ReflectiveAccessorOptimizer.java:140)
    + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************

INFO  2014-11-12 15:37:18,095 [[rollbacktest].rollbacktestFlow2.stage1.02] org.mule.api.processor.LoggerMessageProcessor: Rollbacktestflow 2

The exhausted logger is not getting called, instead the Rollbacktestflow2 logger in the initial flow is called.

Can anyone explain why? Thanks


Solution

  • Why the rollback-exception-strategy doesn't retry?:

    The rollback-exception-strategy behaves differently depending on if the flow has a transaction or not, and on the kind of inbound connector ( transactional or reliable ). To be able to reprocess the message, you need an inbound transport, so the rollback-exception-strategy can either rollback the transaction ( transactional transport with an open transaction ) or discard the message and try again ( reliable transport )

    In your example you don't have an inbound connector on the second flow, so the rollback-exception-strategybehaves as section "Use Rollback Exception Strategy for Unhandled Exceptions" on the mule doc describes: "When the flow exchange pattern is request-response, rollback exception strategy changes the payload of a message and returns it to the client" Although the doc is not explicit, when the flow doesn't have an inbound connector the rollback-exception-strategy doesn't retry.

    If you want to implement a flow that retries, you can use a vm transport between the two flows.

    Example:

    <mule xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
        xmlns:vm="http://www.mulesoft.org/schema/mule/vm"
        xmlns:https="http://www.mulesoft.org/schema/mule/https"
        xmlns:file="http://www.mulesoft.org/schema/mule/file"
        xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
        xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.5.1"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
    http://www.mulesoft.org/schema/mule/https http://www.mulesoft.org/schema/mule/https/current/mule-https.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
    http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
    http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd
    http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd">
    
    
    <file:connector name="File" autoDelete="true" streaming="false" validateConnections="true" doc:name="File"/>
    
    <flow name="pickFiles" >
        <file:inbound-endpoint path="/Users/ramiro/tmp/rollback/in" responseTimeout="10000" doc:name="File" connector-ref="File"/>
        <logger message="File Rx" level="INFO" doc:name="FileRx"/>
        <vm:outbound-endpoint path="buffer" exchange-pattern="one-way" doc:name="VM"/>        
    
        <catch-exception-strategy doc:name="Catch Exception Strategy">
            <logger message="Rollbacktestflow 2" level="INFO" doc:name="Rollbacktestflow2"/>
        </catch-exception-strategy>
    </flow>
    
    <flow name="processQueue"  >
        <vm:inbound-endpoint path="buffer" exchange-pattern="one-way" doc:name="VM">
            <vm:transaction action="ALWAYS_BEGIN" />
        </vm:inbound-endpoint>
        <logger message="about to throw Exception..." level="INFO" doc:name="RollbackTrigger"/>
    
        <scripting:component doc:name="throw Exception">
            <scripting:script engine="Groovy"><![CDATA[
                throw new Exception('some very bad error')
            ]]></scripting:script>
        </scripting:component>
    
        <!-- we never get here -->
        <file:outbound-endpoint path="/Users/ramiro/tmp/rollback/success " doc:name="dlq" connector-ref="File"/>
    
        <rollback-exception-strategy maxRedeliveryAttempts="4" doc:name="Rollback Exception Strategy">
            <logger message="retry" level="INFO" doc:name="retry"/>
            <on-redelivery-attempts-exceeded >
                <logger message="exhausted" level="INFO" doc:name="exhausted"/>
                <file:outbound-endpoint path="/Users/ramiro/tmp/rollback/dlq" doc:name="dlq" connector-ref="File"/>
            </on-redelivery-attempts-exceeded>
        </rollback-exception-strategy>
    </flow>
    
    
    
    </mule>
    

    Here we get a file and send it via a vm transport. The second flow picks the message from the vm and if there's an exception ( always in the example ), will abort the transaction and try to process again the message, and if it fails 4 times then send it to a DLQ.

    About until-successful

    You say that you used until-successful as a workaround. In my opinion using rollback-exception-strategy is more appropriate when you have a unit of work that you need to handle as a transaction ( maybe a flow with several transformations and enrichments ), and until-successful when you just need to retry a step that may fail ( like calling a REST service that may fail because of a temporary network condition )