...
For example if you want to perform a specific piece of processing if a certain exception is raised you can do this simply via:
...
Here if the processing of seda:inputA
or seda:inputB
cause a ValidationException
to be thrown (such as due to the XSD validation of the Validation component or the Relax NG Compact syntax validation of the Jing component), then the message will be sent to the activemq:validationFailed
queue.
You can define multiple onException
clauses for different behavior:
...
Scopes
Exception clauses is scoped as either:
...
Global scope for Java DSL is per RouteBuilder
instance, so if you want to share among multiple RouteBuilder
classes, then create a base abstract RouteBuilder
class and put the error handling logic in its configure
method. And then extend this class, and make sure to class super.configure()
. We are just using the Java inheritance technique.
...
This is best illustrated with an exception:
...
In the sample above we have defined two exceptions in which IOException
is first, so Camel will pickup this exception if there is a match. IOException
that is more general is selected then.
So if an exception is thrown with this hierarchy:
...
...
Then Camel will try testing the exception in this order: FileNotFoundException
, IOException
, OrderFailedException
and RuntimeCamelException
.
As we have defined a onException(IOException.class)
Camel will select this as it's the closest match.
If we add a third onException
clause with the FileNotFoundException
...
Then with the previous example Camel will now use the last onException(FileNotFoundException.class)
as its an exact match. Since this is an exact match it will override the general IOException
that was used before to handle the same exception thrown.
Now a new situation if this exception was thrown instead:
...
Then the onException(OrderFailedException.class)
will be selected - no surprise here.
And this last sample demonstrates the instanceof
test aspect in which Camel will select an exception if it's an instance of the defined exception in the onException
clause. Illustrated as:
...
Since SocketException
is an instanceof IOException
, Camel will select the onException(IOException.class)
clause.
...
By default any Exception Clause will not redeliver! (as it sets the maximumRedeliveries
option to 0).
...
However if you want to customize any methods on the RedeliveryPolicy object, you can do this via the fluent API. So lets retry in case of org.apache.camel.ValidationException
up till two times.
...
Java DSL:
...
And the spring Spring XML DSL:
...
...
You can customize any of the RedeliveryPolicy so we can for instance set a different delay of 5000
millis:
...
Point of Entry for Redelivery Attempts
All redelivery attempts start at the point of the failure. So the route:
...
Will retry from processor2
- not the complete route.
...
Available as of Camel 1.5.1 or later
You can reference a RedeliveryPolicy
so you can reuse existing configurations and use standard spring bean style configuration that supports property placeholders.
...
...
Asynchronous Delayed Redelivery
...
In Camel 1.5 the exception clauses has been renamed to onException
and it also supports multiple exception classes:
...
And in Spring DSL you just add another exception element:
...
:
...
Using a Processor as a Failure Handler
We want to handle certain exceptions specially so we add a onException
clause for that exception. Wiki Markup MyFunctionalException
is thrown it is being routed to our processor MyFunctionFailureHandler
. So you can say that the exchange is diverted when a MyFunctionalException
is thrown during processing. It's important to distinct this as perfect valid. The default redelivery policy from the Dead Letter Channel will not kick in, so our processor receives the Exchange directly, without any redeliver attempted. In our processor we need to determine what to do. Camel regards the Exchange as failure handled. So our processor is the end of the route. So lets look the code for our processor. Wiki Markup
...
See also the section Handle and continue exceptions below
...
For instance to mark all ValidationException
as being handled we can do this:
...
Example Using Handled
In this route below we want to do special handling of all OrderFailedException
as we want to return a customized response to the caller. First we setup our routing as: Wiki Markup API: Wiki Markup Wiki Markup
If we sent an order that is being processed OK then the caller will receive an Exchange as reply containing Order OK
as the payload and orderid=123
in a header.
...
The same route as above in Spring DSL: Wiki Markup
Handling and Sending a Fixed Response Back to the Client
In the route above we handled the exception but routed it to a different endpoint. What if you need to alter the response and send a fixed response back to the original caller (the client). No secret here just do as you do in normal Camel routing, use transform to set the response, as shown in the sample below: Wiki Markup Wiki Markup Wiki Markup
Handle and Continue Exceptions
...
For example: to ignore and continue when the IDontCareException
was thrown we can do this:
...
You can maybe compare continued with a having a try ... catch
block around each step and then just ignore the exception. Using continued makes it easier in Camel as you otherwise had to use Try Catch Finally style for this kind of use case.
...
In this route below we want to do special handling of all IllegalArgumentException
as we just want to continue routing. Wiki Markup Wiki Markup
What is the Difference Between Handled and Continued?
...
For example: if you have this route:
...
...
The route listen for JMS messages and validates, transforms and handle it. During this the Exchange payload is transformed/modified. So in case something goes wrong and we want to move the message to another JMS destination, then we can add an onException
. But when we move the Exchange to this destination we do not know in which state the message is in. Did the error happen in before the transformOrder
or after? So to be sure we want to move the original input message we received from jms:queue:order:input
. So we can do this by enabling the useOriginalMessage
option as shown below:
...
...
Then the messages routed to the jms:queue:order:failed
is the original input. If we want to manually retry we can move the JMS message from the failed to the input queue, with no problem as the message is the same as the original we received.
...
The useOriginalMessage
option is defined as a boolean attribute on the <onException>
XML tag in Spring DSL. So the definition above would be:
...
...
Advanced Usage of Exception Clause
...
We start off with the sample sample that we change over time. First off we use only global exception clauses: Wiki Markup
...
Important: This requires to end the onException
route with .end()
to indicate where it stops and when the regular route
...
continues.
Wiki Markup MyFunctionalException
in both routes, but they are configured differently and thus is handled different depending on the route. You can of course also add a new onException
to one of the routes so it has an additional exception policy.
And finally we top this by throwing in a nested error handler as well, as we add the 3rd route shown below: Wiki Markup
...
The sample above with both nested error handlers and both global and per route exception clauses is a bit advanced. It's important to get the fact straight that the global exception clauses is really global so they also applies for nested error handlers. So if a MyTechnicalException
is thrown then it's the global exception policy that is selected.
Using Fine Grained Selection Using onWhen
Predicate
...
You can attach an Expression to the exception clause to have fine grained control when a clause should be selected or not. As it's an Expression you can use any kind of code to perform the test. Here is a sample: Wiki Markup onException
's defined. The first has an onWhen
expression attached to only trigger if the message has a header with the key user that is not null. If so this clause is selected and is handling the thrown exception. The second clause is a for coarse gained selection to select the same exception being thrown but when the expression is evaluated to false.
...
In the code below we want to do some custom code before redelivering any IOException
. So we configure an onException
for the IOException
and set the onRedelivery
to use our custom processor: Wiki Markup Wiki Markup
Using onRedelivery
in Spring DSL
In Spring DSL you need to use the onRedeliveryRef
attribute to refer to a spring bean id that is your custom processor: Wiki Markup $
for the inner class as this code is based on unit testing): testing): Wiki Markup
Using onExceptionOccurred
Processor
...
In the code below we want to do some custom logging when an exception happened. Therefore we configure an onExceptionOccurred
to use our custom processor:
...
Using onRedelivery
in Spring DSL
In Spring DSL you need to use the onExceptionOccurredRef
attribute to refer to a spring bean id that is your custom processor:
...
...
Using Fine Grained Retry Using retryWhile
Predicate
Available as of Camel 2.0
...
...
In Camel 2.0 to 2.3 its called retryUntil
. From Camel 2.4: its named retryWhile
because Camel will continue doing retries while the predicate returns true.
When you need fine grained control for determining if an exchange should be retried or not you can use the retryWhile
predicate. Camel will redeliver until the predicate returns false.
Example: Wiki Markup myRetryHandler
is computing if we should retry or not: Wiki Markup
Using Custom ExceptionPolicyStrategy
...
The default ExceptionPolicyStrategy in Camel should be sufficient in nearly all use-cases (see section How does Camel select which clause should handle a given thrown Exception). However, if you need to use your own this can be configured as the sample below illustrates: Wiki Markup MyPolicy
we can change the default behavior of Camel with our own code to resolve which ExceptionType from above should be handling the given thrown exception. Wiki Markup
Using the Exception Clause in Spring DSL
...
Global scoped - Available in Camel 2.0
Wiki Markup {snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/onexception/deadLetterChannelHandledExampleTest.xml}
Route specific scoped
Wiki Markup {snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/onexception/onExceptionSubRouteTest.xml}
See also
The Error Handler for the general error handling documentation
The Dead Letter Channel for further details.
The Transactional Client for transactional behavior