Java 8/Camel 2.19.x/AMQ 5.15.x here.
I have a Java app that uses Camel to consume messages off of AMQ queues, process those messages, and do stuff with them. Sometimes the output of a route is putting the processing result back up on another queue for further downstream processing, but not always/necessarily. Typical Java/Camel/AMQ setup.
Each of my routes (I'm using the Camel XML DSL) has a configured <onException>
handler, which typically looks like this:
<onException useOriginalMessage="true">
<exception>java.lang.Exception</exception>
<redeliveryPolicy logStackTrace="true"/>
<handled>
<constant>true</constant>
</handled>
<log message="${exception.stacktrace}" loggingLevel="ERROR"/>
<rollback markRollbackOnly="true"/>
</onException>
So pretty simple: log the exception and rollback.
What I would like to do is, as part of this <onException>
handler, to place the original message (that failed and caused the exception to be thrown, not the exception!) on a route-specific DLQ (by "DLQ" I mean just a queue where failed messages can be sent for auditing/reporting/playback purposes)
Meaning, if my app has 30 routes that each consume from 30 different AMQ queues, I would have 30 different "DLQs" where each of their respective <onException>
handlers would send the failing messages to.
Ideally I'd like this configuration to be on the AMQ side (again perhaps inside of activem.xml
or similar) so that I don't need to make code changes or redeploys if the DLQ destinations need to change. But if its only possible to do from inside the Camel route/configs, that's fine too.
I suppose I could modify each route to contain its own customized destination DLQ for the original messages:
<onException useOriginalMessage="true">
<exception>java.lang.Exception</exception>
<redeliveryPolicy logStackTrace="true"/>
<handled>
<constant>true</constant>
</handled>
<log message="${exception.stacktrace}" loggingLevel="ERROR"/>
<rollback markRollbackOnly="true"/>
<to uri="activemq:fizzbuzz.dlq"/>
</onException>
But I'm hoping for something more elegant than this...
Any ideas how I can do this?
May be this way will be better for you:
DeadLetterChannelBuilder errorHandlerBuilder = deadLetterChannel("jms:dummy");
errorHandlerBuilder.onPrepareFailure(exchange -> {
exchange.getIn().setHeader("CamelJmsDestinationName",exchange.getIn().getHeader("JMSDestination",String.class).concat(".DLQ"));
});
from("jms:input1")
.to("seda:process");
from("jms:input2")
.to("seda:process");
from("jms:input3")
.to("seda:process");
from("seda:process").errorHandler(errorHandlerBuilder)
.process(exchange -> {
throw new RuntimeException();
});
You can compute DLQ queue name in runtime. DeadLetterChannelBuilder can be configured like your onException as well.