If you use JMS then the JMS broker has built in support for error queues (dead letter channel). So its in fact better to use that, instead of having Camel sending the message back to the error queue. Then all that is handled within the broker.
See chapter 9 in the Camel in Action book.
The Apache ActiveMQ web site have a few details as well
Then you dont need to use the onException at all.
Thanks for the suggestion Claus. I changed my code to route my failed message to a dead letter queue:
This successfully routed the origianl message to my error queue BUT the UnitOfWork was again called with the onComplete() message.
No matter what I try, it appears that the only way the onFailure() message will be called for the UnitOfWork is if Camel catches an Exception. Any of the Camel features to manually handle an exception seem to prevent the UnitOfWork from failing.
Clearly I am missing something. The UnitOfWork seems to be the right Camel construct for handling processing that needs to be commited or rolled back based on the success or failure of the Camel route. But what are the conditions under which onFailure will be called?
The UnitOfWork is executed at the very end. After onException or any errorHandler which may have been invoked.
I was actually suggesting to not use the Camel errorHandler at all, but rely on the JMS broker to use its dead letter queue feature. The JMS Broker can be configured to move failed messages to a selected dead letter queue in case a consumer cannot process it successfully. The JMS broker have similar options as Camel in terms of number of redelivery attempts, delays between redeliveries, etc. When you use that its more safer as its all handled within the JMS broker itself.
If you let Camel do it, then its JMS -> Camel -> JMS.
If you let the JMS broker use its dead letter queue, then you can keep the UnitOfWork logic, as the exchange will still fail at the end, so it causes a rollback on the transaction, which is propagated back to the JMS broker, so it knows the TX failed.
That means the exchange will failed at the end, and the UnitOfWork will invoke the onFailed method, where you can delete the file.
If doing this you do not need to use the onException, errorHandler etc at all.
In terms of if you want to use as your very first suggestion
Then you can move the logic that you do with the UnitOfWork into this piece. Such as using a processor to delete the file.
onException(Exception.class).handled(true).process(new MyDeleteFileProcessor()). to("myErrorQueue").end()
Then the deleting becomes part of this logic above.
If you look at this unit test example from the book
Then the testNoConnectionToDatabase shows a situation where the message will fail all the time, and eventually be moved in the DLQ of the JMS broker. The default DLQ is named "ActiveMQ.DLQ". You can configure this to be another name, or to use a DLQ per queue using some sort of prefix/suffix syntax.