Exchange state gets OK in a Camel route even after a fault thrown in SwitchYard

Solution Verified - Updated -

Environment

  • Red Hat JBoss Fuse Service Works (FSW)
    • 6.0

Issue

  • In a SwitchYard Camel route, the Exchange state can get OK even though a fault has happened before.
  • We have two Camel routes. The second route calls some external web service, which returns a SOAP fault. When this is handed back over to the first route the content type and the state change in the Exchange.
  • Look at the output. At some point it switches over to a fault, and shows the expected content type:

    ...
    State -> FAULT
    ...
    org.switchyard.bus.camel.fault .................: true
    ...
    org.switchyard.contentType ................: {urn:switchyard-quickstart:camel-soap-proxy:1.0}exceptionInfo
    ...
    
  • Then, later on in the chain you will see the following:

    State -> OK
    ...
    org.switchyard.contentType ..........: {urn:switchyard-quickstart:camel-soap-proxy:1.0}reverseResponse
    ...
    
  • This is unexpected behaviour. The state and content type should not be lost. The reason for that is, that we registered some transformers in switchyard.xml based on the content type. If the content type is 'response', but the actual message content is 'fault', the transformers are getting called with unexpected data and fail. Our expectation would be that we do not handle the fault, and it is propagated back through the chain, as we do not handle it.

  • Another interesting fact we noticed. This only happens with the doTry and doCatch blocks. If we remove them completely, we see the expected behaviour. Removing those blocks is not an option though, as it would mean that there is no handling for Java exceptions anymore.
  • Proposed two different solutions:
    1. Adding handleFault=true to the route -- This would mean that the fault message is handled in the doCatch block. We do not want this though. Instead we want the fault to be propagated.
    2. Adding handled to doCatch -- This does not apply, as this only works once the handleFault=true attribute is set.

Resolution

Apply the roll-up patch FSW_6.0_1_2015 or later, or upgrade to Fuse 6.2.1 (when it is released).

Workaround

If applying the roll-up patch is temporarily impossible, then one workaround is to add a <log> step right after the </doTry> tag as follows:

  <route>
    ...
    <doTry>
      ...
      <doCatch>
        ...
      </doCatch>
    </doTry>
    <log message="..." /> <!-- Add here -->
    ...
  </route>

Root Cause

This is a bug in Apache Camel:

This is actually a peculiarity of how try/catch works in Camel. The TryProcessor has some logic where it iterates over each processor in the try/catch/finally blocks and on each iteration it sets the out message as the in message and clears the out message reference. If the TryProcessor is the final processor in a route, this results in the out message being cleared when the route completes regardless of MEP. Unfortunately, the isFailed() method on DefaultExchange only looks at the out message for a fault. SwitchYard checks whether an exchange is failed to see whether to mark the SwitchYard exchange state as FAULT, so you can see where things go bad here.

With regard to the workaround, adding a processor after the try/catch block triggers code within Pipeline to actually check if the MEP is in-out, and if it is, to copy the in message reference to the out message reference. This results in isFailed() returning the correct value.

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Comments