Red Hat Training

A Red Hat training course is available for Red Hat Fuse

2.11. OnCompletion

Overview

The OnCompletion DSL name is used to define an action that is to take place when a Unit of Work is completed. A Unit of Work is a Camel concept that encompasses an entire exchange. See Section 43.1, “Exchanges”. The onCompletion command has the following features:
  • The scope of the OnCompletion command can be global or per route. A route scope overrides global scope.
  • OnCompletion can be configured to be triggered on success for failure.
  • The onWhen predicate can be used to only trigger the onCompletion in certain situations.
  • You can define whether or not to use a thread pool, though the default is no thread pool.

Route Only Scope for onCompletion

When an onCompletion DSL is specified on an exchange, Camel spins off a new thread. This allows the original thread to continue without interference from the onCompletion task. A route will only support one onCompletion. In the following example, the onCompletion is triggered whether the exchange completes with success or failure. This is the default action.
from("direct:start")
     .onCompletion()
         // this route is only invoked when the original route is complete as a kind
         // of completion callback
         .to("log:sync")
         .to("mock:sync")
     // must use end to denote the end of the onCompletion route
     .end()
     // here the original route contiues
     .process(new MyProcessor())
     .to("mock:result");
For XML the format is as follows:
<route>
    <from uri="direct:start"/>
    <!-- this onCompletion block will only be executed when the exchange is done being routed -->
    <!-- this callback is always triggered even if the exchange failed -->
    <onCompletion>
        <!-- so this is a kinda like an after completion callback -->
        <to uri="log:sync"/>
        <to uri="mock:sync"/>
    </onCompletion>
    <process ref="myProcessor"/>
    <to uri="mock:result"/>
</route>
To trigger the onCompletion on failure, the onFailureOnly parameter can be used. Similarly, to trigger the onCompletion on success, use the onCompleteOnly parameter.
from("direct:start")
     // here we qualify onCompletion to only invoke when the exchange failed (exception or FAULT body)
     .onCompletion().onFailureOnly()
         .to("log:sync")
         .to("mock:sync")
     // must use end to denote the end of the onCompletion route
     .end()
     // here the original route continues
     .process(new MyProcessor())
     .to("mock:result");
For XML, onFailureOnly and onCompleteOnly are expressed as booleans on the onCompletion tag:
<route>
    <from uri="direct:start"/>
    <!-- this onCompletion block will only be executed when the exchange is done being routed -->
    <!-- this callback is only triggered when the exchange failed, as we have onFailure=true -->
    <onCompletion onFailureOnly="true">
        <to uri="log:sync"/>
        <to uri="mock:sync"/>
    </onCompletion>
    <process ref="myProcessor"/>
    <to uri="mock:result"/>
</route>

Global Scope for onCompletion

To define onCompletion for more than just one route:
// define a global on completion that is invoked when the exchange is complete
 onCompletion().to("log:global").to("mock:sync");

 from("direct:start")
     .process(new MyProcessor())
     .to("mock:result");

Using onWhen

To trigger the onCompletion under certain circumstances, use the onWhen predicate. The following example will trigger the onCompletion when the body of the message contains the word Hello:
/from("direct:start")
     .onCompletion().onWhen(body().contains("Hello"))
         // this route is only invoked when the original route is complete as a kind
         // of completion callback. And also only if the onWhen predicate is true
         .to("log:sync")
         .to("mock:sync")
     // must use end to denote the end of the onCompletion route
     .end()
     // here the original route contiues
     .to("log:original")
     .to("mock:result");

Using onCompletion with or without a thread pool

As of Camel 2.14, onCompletion will not use a thread pool by default. To force the use of a thread pool, either set an executorService or set parallelProcessing to true. For example, in Java DSL, use the following format:
onCompletion().parallelProcessing()
     .to("mock:before")
     .delay(1000)
     .setBody(simple("OnComplete:${body}"));
For XML the format is:
<onCompletion parallelProcessing="true">
   <to uri="before"/>
   <delay><constant>1000</constant></delay>
   <setBody><simple>OnComplete:${body}<simple></setBody>
 </onCompletion>
Use the executorServiceRef option to refer to a specific thread pool:
<onCompletion executorServiceRef="myThreadPool"
   <to uri="before"/>
   <delay><constant>1000</constant></delay>
   <setBody><simple>OnComplete:${body}</simple></setBody>
 </onCompletion>>

Run onCompletion before Consumer Sends Response

onCompletion can be run in two modes:
  • AfterConsumer - The default mode which runs after the consumer is finished
  • BeforeConsumer - Runs before the consumer writes a response back to the callee. This allows onCompletion to modify the Exchange, such as adding special headers, or to log the Exchange as a response logger.
For example, to add a created by header to the response, use modeBeforeConsumer() as shown below:
.onCompletion().modeBeforeConsumer()
     .setHeader("createdBy", constant("Someone"))
 .end()
For XML, set the mode attribute to BeforeConsumer:
<onCompletion mode="BeforeConsumer">
   <setHeader headerName="createdBy">
     <constant>Someone</constant>
   </setHeader>
 </onCompletion>