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.
Related
I have an Apache Camel route which invokes restlet component. To better understand what is happening at runtime I also keep the execution state in a database (number of retries, last execution state). I would like to use the redelivery mechanism from the exception handler but which performs some processing on every failure to update my database record.
<bean class="com.tcl.ExceptionOccurredRefProcessor" id="exProc" />
<camelContext errorHandlerRef="eh">
<errorHandler id="eh" onExceptionOccurredRef="exProc"> <redeliveryPolicy
maximumRedeliveries="3" maximumRedeliveryDelay="2000"
retryAttemptedLogLevel="WARN" />
</errorHandler>
<to uri="-------"/> //Invoke rest service
<onException id="_onException1" onExceptionOccurredRef="exProc" useOriginalMessage="true">
<exception>java.lang.Exception</exception>
<handled>
<simple>true</simple>
</handled>
...........
</onException>
</camelContext>
For this I tried to use onExceptionOccurred component with redelivery component and referred on camelContext as in above code but the message got delivered only once and stopped the execution.
Any suggestions please?
First of all: the code you pasted is a bit confusing because there is no Camel route, just a plain to element that cannot be alone in the Camel context.
However, I guess your problem is a "hidden" Camel handling. As documented in the Camel Docs of the Exception Clause, the onException clause overrides the maximumRedeliveries to 0 by default unless you explicitly set the option.
<onException>
<exception>java.lang.Exception</exception> // max. redelivery = 0
</onException>
<onException>
<exception>java.lang.Exception</exception>
<redeliveryPolicy maximumRedeliveries="3"/> // max. redelivery = 3
</onException>
I an not sure about the other redelivery options like maximumRedeliveryDelay, but at least the maximumRedeliveries is overridden if not explicitly set.
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 read the corresponding documentation but I couldn't figure out why my Exception is not catched.
This is my route configuration:
<route id="foo">
<from uri="vm://.../>
<doTry>
<to uri="jetty:http://127.0.0.1:123/foo?restletMethod=PUT"/>
<to uri="ejb:java:global/..?method=method1(${body}, ${headers})"/>
<to uri="ejb:java:global/..?method=method2(${body}, ${headers})"/>
<doCatch>
<exception>java.lang.Exception</exception>
<transform>
<simple> ${exception.message} </simple>
</transform>
<to uri="smtp://... />
</doCatch>
</doTry>
</route>
Now when the JettyClient is not reachable a org.apache.camel.CamelExchangeException is thrown,
the route terminates and I receive an email. This is the desired behaviour.
But when method1 throws an exception it is not catched, hence the route continues and
I don't receive an email.
How can I make camel recognize and handle the exception in the second case too?
Solution: Make sure the exception isn't thrown inside a try-catch block -.-
This is stated in the documentation:
http://camel.apache.org/try-catch-finally.html
Camel error handling is disabled
When using doTry .. doCatch .. doFinally then the regular Camel Error
Handler does not apply. That means any onException or the likes does
not trigger. The reason is that doTry .. doCatch .. doFinally is in
fact its own error handler and that it aims to mimic and work like how
try/catch/finally works in Java.
You are probably better off to write it like this:
.doCatch(Exception.class)
// and catch all other exceptions
// they are handled by default (ie handled = true)
.to("direct:error")
In direct:error you can specify what to do in case something goes wrong.
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")...
I'm trying to retrieve the stacktrace from the onException handler in Apache Camel:
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<setHeader headerName="exception">
<simple>${exception}</simple>
</setHeader>
</onException>
However, the above only shows the exception rather than the entire stacktrace.
I understand that Camel stores the caught exception as a property on the Exchange with the key: Exchange.EXCEPTION_CAUGHT, but how can this be retrieved from the camel context routes file ?
Use exception.stacktrace to get the stacktrace. See the variables listed in the table at this page: http://camel.apache.org/simple
<simple>${exception.stacktrace}</simple>
There is also a ${exception.message} to refer to the exception message itself.