I noticed that after successful doTry/doCatch handling global onException handler is no longer invoked. Here's my sample code:
<doTry>
<to uri="direct:triggerError"/>
<doCatch>
<exception>com.foo.bar.MyException</exception>
<log message="IN DOCATCH"/>
</doCatch>
<doFinally>
<log message="IN FINALLY"/>
</doFinally>
</doTry>
<throwException message="Now handle it in global handler" exceptionType="com.foo.bar.MyOtherException"/>
And in my camel context I have this:
<onException>
<exception>com.foo.bar.MyOtherException</exception>
<handled>
<constant>true</constant>
</handled>
<log message="HANDLING MY OTHER EXCEPTION"/>
<to uri="direct:commonAPIErrorProcessor"/>
</onException>
What I observe is the exception is properly caught in doCatch and doFinally is invoked, but the global onException is never called and I get a stack trace in response. How can I fix it?
I tried it with Camel 3.4.0 and 3.7.0, same results.
The problem in your example is that you call another route within doTry. This seems to confuse the Camel no matter if you use XML or Java DSL (in both DSLs the same effect).
As long as you use simple "statements" in doTry, everything works perfect. When you call another route, it is as you describe very confusing.
Camel catches the exception thrown by the other route, but afterwards the error handler stays "disabled". It seems like Camel loses the doTry scope and therefore never finishes the "error handling disabled state" that is enabled by doTry.
I therefore assume that the "route jump" is not the intended use case for doTry/doCatch. Since it overwrites the normal error handling, it should probably be used only very locally within a route.
I'm calling out to a WS using cxf:cxfEndpoint and its working fine. I want to catch any exceptions using onException or something similar. For some reason its not working. I have set the dataFormat to PAYLOAD, handleFault attribute on the route and/or the camel context to true. The web service is not running so I'm expecting the exception to be caught but its not working. Same issue with unmarshalling of the XML.
When I throw an exception using it gets caught successfully using java.lang.Exception and written to my dummy exception queue... but when the webservice is down or I pass in some invalid XML and the marshalling fails then an exception gets thrown but not caught.
Is there anything else to be aware of?
EDIT: Included the code for unmarshaling. Switched to using Try/Catch and when i pass in invalid XML the exception does get caught during the junit testing but does not get caught at runtime
<route>
<from uri="jmsamq:In"/>
<doTry>
<unmarshal>
<jaxb contextPath="outbound.message"/>
</unmarshal>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<transform>
<simple>Mapping Failed</simple>
</transform>
<to uri="jmsamq:errorqueue1"/>
</doCatch>
</doTry>
<log message="${body}"/>
<multicast stopOnException="true">
<to uri="direct:webservice"/>
<to uri="direct:myqueue"/>
</multicast>
</route>
the incorrect camel-context XML file was being used at runtime.. ignore question!
I have my camel setup along the lines of:
<route>
<from ur="servlet:///test"/>
<to uri="direct:check1"/>
<to uri="direct:check2"/>
<to uri="direct:check3"/>
<to uri="direct:myprocessor"/>
</route>
Since I'm setting this up as a request/reply (in-out) pattern, I'm confused around if there is a process-stopping issue on check1, 2, or 3 on one specific message/exchange how to 'fast fail' a response back without going through the rest of the routes?
Throwing exceptions and using the onException DSL will achieve what you need. If you throw an exception in one of the checks it will be caught in the onException block without going further through the rest of the route.
I have the onException block below that worked before I upgraded to from camel 2.14 to camel 2.16.1. Before the update, I would get my error caught and printed in the log - "Error posting to MR". After I upgraded to camel 2.16.1, I still get my error in the log, but now, always, my handled error is followed by another timestamp with what appears to be camel default error handler for the error I think I already handled. It looks like this:
"2016-01-26 15:07:09,571 [Camel (mrPostContext) thread #56 - JmsConsumer[mrPost]] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId"....
I don't know if I'm doing something wrong, I tried using java.lang.Throwable instead of java.lang.Exception but so far had no luck. Haven't found anything helpful in documentation yet. As I'm far from being good with camel, I will much appreciate some help.
<route id="mrPost">
<from uri="activemq:mrPost?concurrentConsumers=8" />
<onException>
<exception>java.lang.Exception</exception>
<redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="1000"/>
<handled>
<constant>true</constant>
</handled>
<to uri="activemq:mr-post-fail" />
<log loggingLevel="ERROR" message="Error posting to MR body:${out.body} exception message: ${exception.message} body:${exception.responseBody}" />
</onException>
<setHeader headerName="CamelHttpMethod">
<constant>PUT</constant>
</setHeader>
<recipientList>
<simple>{{mr.source}}/${headers.id}</simple>
</recipientList>
</route>
Here is a much cleaner solution in case someone is looking for it:
<errorHandler id="loggingErrorHandler" type="LoggingErrorHandler" logName="LoggingErrorHandler" level="OFF"/>
<camelContext id="mrPostContext" trace="false" errorHandlerRef="loggingErrorHandler" >
I think that camel is failing where it puts the message on to the error queue mr-post-fail and is throwing an exception when doing so, hence your exception is propogating to the DefaultExceptionHandler. Since the logging is after the put queue call it is not working as you expected.
If not the case can you give the whole line of the error thats being printed.
"2016-01-26 15:07:09,571 [Camel (mrPostContext) thread #56 - JmsConsumer[mrPost]] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId"..
I got the defaultErrorHandler to collapse with these 2 adjustments:
- set messageHistory="false" on CONTEXT
- set logStackTrace="false" for onException block, like this:
<redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="1000" logStackTrace="false" />
The timestamp with default error handler still shows up, but much easier on the eye, it looks like this:
2016-02-01 11:26:27,792 [Camel (mrPostContext) thread #262 - JmsConsumer[mrPost]] ERROR org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId: ID-qn7nwscms01-com-44939-1454025367155-1569-4 on ExchangeId: ID-qn7nwscms01-com-44939-1454025367155-1569-5). Exhausted after delivery attempt: 3 caught: org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking http://mr.cloud.dig.com/api/contents/news/30939510 with statusCode: 409. Processed by failure processor: FatalFallbackErrorHandler[Pipeline[[Channel[SetHeader(CamelExceptionCaught, Simple: Headers: ${headers} Message: ${exception.message} Body: ${exception.responseBody})], Channel[sendTo(Endpoint[activemq://mr-post-fail])], Channel[choice{when Filter[if: Simple: ${exception.message} not contains "statusCode: 409" do: Pipeline[[Channel[SetHeader(Content-Type, text/plain)], Channel[SetHeader(to, Simple: lw#ac.com)], Channel[SetHeader(subject, Simple: Error posting to MR)], Channel[SetBody(Simple: ${header.CamelExceptionCaught})]]]]}], Channel[Log(mrPost)[Error posting to MR ID: ${headers.contentId}, type:${headers.cmsContentType}, modified:${headers.lastModifiedDate}, getTime:${headers.lastModifiedGetTime}]], Channel[Log(merlinPost)[Error posting to MR body:${out.body} exception message: ${exception.message} body:${exception.responseBody}]]]]]
I hope there is a way to turn it off completely.
I also tried using defaultErrorHandler setup:
<errorHandler id="defaultErrorHandler" type="DefaultErrorHandler">
<redeliveryPolicy logStackTrace="false"/>
</errorHandler>
but it makes no impact.
You can use like the example in this page: http://camel.apache.org/exception-clause.html
<!-- setup our error handler as the deal letter channel -->
<bean id="errorHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
<property name="deadLetterUri" value="activemq:mr-post-fail"/>
</bean>
<!-- this is the camel context where we define the routes -->
<!-- define our error handler as a global error handler -->
<camelContext errorHandlerRef="errorHandler" xmlns="http://camel.apache.org/schema/spring">
<route>
<!-- the route -->
<from uri="activemq:mrPost?concurrentConsumers=8" />
<setHeader headerName="CamelHttpMethod">
<constant>PUT</constant>
</setHeader>
<recipientList>
<simple>{{mr.source}}/${headers.id}</simple>
</recipientList>
</route>
</camelContext>
Or, set in rote, to the error handle work only with an specific route
<route errorHandlerRef="errorHandler">
...
</route>
And remove from camelContext
I have two routes - each in a different camel context:
<camelContext id="camelContext1" xmlns="http://camel.apache.org/schema/blueprint">
<onException>
<exception>com.me.MyException</exception>
<to uri="log:osgiExecutorLog"/>
</onException>
<route id="MyRoute">
<from uri="amq:test" />
<to uri="direct:MyDirect"/>
</route>
</camelContext>
<camelContext id="camelContext2" xmlns="http://camel.apache.org/schema/blueprint">
<route id="MyRoute">
<from uri="direct:MyDirect" />
<process ref="myProc"/>
</route>
</camelContext>
There are conditions where myProc will throw MyException and I want the onException in camel context 1 to catch that. I tried my luck hard but could not get that to work; is it like catching exceptions across camel contexts not supported or am I missing something?
Instead of trying to throw an exception back to the other context (which may or may not even be possible due to the mechanisms in camel 2.x) you could catch the exception and send a message to some sort of error handling endpoint.
This can be easily defined in a different route builder or context, as long as you know the endpoint name.
Each route then has exactly the same boilerplate exception handler at the top, for example:
onException(Exception.class).handled(true).to("direct-vm:errors")
We routinely use this sort of custom error handling between different route builders (in the same context, but the pattern can apply across contexts just as easily).
In our application, for example, we catch the exceptions, aggregate them in a list, and whenever 15 seconds goes by without a new exception we send an email via smtp - all too easy with a camel route defined as from("direct:errors")...