...
Camel has this concept of a Unit of Work that encompass the Exchange. The unit of work among others supports synchronization callbacks that are invoked when the Exchange is complete. The callback API is defined in org.apache.camel.spi.Synchronization
. From Camel 2.14 onwards : we have an extended synchronization org.apache.camel.spi.SynchronizationRouteAware
that have callbacks for route events.
Tip | ||
---|---|---|
| ||
You can get hold of the |
In Camel 2.0 we have added DSL for these callbacks using the new new onCompletion
DSL name.
onCompletion
supports the following features:
- scopeScope: global and/or per route (route scope override all global scope).
- multiple Multiple global scope.
- triggered Triggered either always, only if completed with success, or only if failed.
onWhen
predicate to only trigger in certain situations.- Camel 2.14: mode Mode: to define whether to run either before or after route consumer writes response back to callee (if its
InOut
). - Camel 2.14: whether Whether to run async or sync (use a thread pool or not).
From Camel 2.14 onwards the : onCompletion
has been modified to support running the completion task in either synchronous or asynchronous mode (using a thread pool) and also whether to run before or after the route consumer is done. The reason is to give more flexibility. For example to specify to run synchronous and before the route consumer is done, which allows to modify the exchange before the consumer writes back any response to the callee. You can use this to for example add customer headers, or send to a log to log the response message, etc.
Info | ||
---|---|---|
| ||
The The
In Camel 2.13 the defaults were
|
Info | |||
---|---|---|---|
| |||
The The Therefore if you want to do some work that influence the original route, then do not use use
|
onCompletion
...
With Route Scope
The The onCompletion
DSL allows you to add custom routes/processors when the original Exchange is complete. Camel spin off a copy of the Exchange and routes it in a separate thread, kinda like a Wire Tap. This allows the original thread to continue while the onCompletion
route is running concurrently. We decided for this model as we did not want the the onCompletion
route to interfere with the original route.
Note | ||
---|---|---|
| ||
You can only have 1 one |
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/OnCompletionTest.java} |
onCompletion
will be triggered when the Exchange is complete and regardless if the Exchange completed with success or with an failure (such as an Exception was thrown). You can limit the trigger to only occur onCompleteOnly
or by onFailureOnly
as shown below:Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/OnCompletionOnFailureOnlyTest.java} |
onCompletion
Exchange as Camel will add the property Exchange.ON_COMPLETION
with a boolean value of true
when it spin offs the the onCompletion
Exchange.Using Using onCompletion
from Spring DSL
The The onCompletion
is defined like this with Spring DSL:
Wiki Markup |
---|
{snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringOnCompletionTest.xml} |
onCompleteOnly
and onFailureOnly
is defined as a boolean attribute on the the <onCompletion>
tag so the failure example would be:Wiki Markup |
---|
{snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringOnCompletionOnFailureOnlyTest.xml} |
onCompletion
...
With Global Scope
This works just like the route scope except from the fact that they are defined globally. An example below:
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/OnCompletionGlobalTest.java} |
Using Using onCompletion
from Spring DSL
This works just like the route scope except from the fact that they are defined globally. An example below:
Wiki Markup |
---|
{snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringOnCompletionGlobalTest.xml} |
Info | ||
---|---|---|
| ||
If an |
...
Using onCompletion
...
with onWhen
...
Predicate
As other DSL in Camel you can attach a Predicate to the the onCompletion
so it only triggers in certain conditions, when the predicate matches.
For example to only trigger if the message body contains the word Hello
we can do like:
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/OnCompletionWhenTest.java} |
...
Using onCompletion
...
With or Without a Threadpool
Available as of Camel 2.14
OnCompletion onCompletion
will from Camel 2.14 onwards : not use thread pool by default. To use thread pool then either set a executorService
or set parallelProcessing
to true
.
For example in Java DSL do:
Code Block | ||
---|---|---|
| ||
onCompletion().parallelProcessing() .to("mock:before") .delay(1000) .setBody(simple("OnComplete:${body}")); |
And in XML DSL:
Code Block | ||
---|---|---|
| ||
<onCompletion parallelProcessing="true"> <to uri="before"/> <delay><constant>1000</constant></delay> <setBody><simple>OnComplete:${body}</simple></setBody> </onCompletion> |
You can also refer to a specific thread pool to be used, using the the executorServiceRef
option:
Code Block | ||
---|---|---|
| ||
<onCompletion executorServiceRef="myThreadPool"> <to uri="before"/> <delay><constant>1000</constant></delay> <setBody><simple>OnComplete:${body}</simple></setBody> </onCompletion> |
...
Using onCompletion
to
...
Run Before Route Consumer Sends Back Response to Callee
Available as of Camel 2.14
OnCompletion onCompletion
supports two modes
AfterConsumer
- Default mode which runs after the consumer is done.BeforeConsumer
- Runs before the consumer is done, and before the consumer writes back response to the callee.
The The AfterConsumer
mode is the default mode which is the same behavior as in older Camel releases.
The new new BeforeConsumer
mode is used to run run onCompletion
before the consumer writes its response back to the callee (if in in InOut
mode). This allows the the onCompletion
to modify the Exchange, such as adding special headers, or to log the Exchange as a response logger etc.
For example to always add a "created by" header you use modeBeforeConsumer()
as shown below:
Code Block | ||
---|---|---|
| ||
.onCompletion().modeBeforeConsumer() .setHeader("createdBy", constant("Someone")) .end() |
And in XML DSL you set the mode attribute to BeforeConsumer
:
Code Block | ||
---|---|---|
| ||
<onCompletion mode="BeforeConsumer"> <setHeader headerName="createdBy"> <constant>Someone</constant> </setHeader> </onCompletion> |
...
See Also
- Unit of Work