ConceptProcess and service activities can be divided into unit-of-works, called transactions that are either executed (i.e. committed) as a whole or undone as a whole (i.e. rollbacked) due to some error or an explicit rollback command. When the activities within the same unit-of-work span multiple resources (databases, Java components, JMS topics, and so on) these resources all need to support global (XA) transactions and need to enlist in the global transaction, to support commits and rollbacks on the transaction as a whole.
It is not always possible to use transactions as a means to commit, or rollback related activities as a whole. For example when the invoked services do not support global transactions. Next to this, long running processes execute several (implicit) commits since transactions shouldn't be kept open too long: this degrades performance and causes completed activities to remain invisible to others. Once a commit has been executed, the committed activities cannot be rollbacked. Consider an Order-to-Process in which we book the customer's credit card in advance and deliver the ordered goods a few days later. The process will dehydrate at some point causing a commit on the active transaction. If delivery of the ordered goods fails we cannot rollback the credit card booking.
Compensation provides a mechanism to undo already committed activities by means of invoking opposite activities (i.e. compensation) in reverse order. For example booking the opposite amount of money to the credit card that was initially charged. SOA Suite provides the following activities to support compensation:
- Compensation handler. Compensation handlers contain the activities that need to be executed as part of the compensation flow. These handlers are defined per scope, similar to catch blocks. Per scope you need decide if you need a compensation handler.
- Compensate activity. The activity that triggers compensation for a SOA Composite. Executing this activity will cause the invocation of compensation handlers for all successfully completed scopes that have defined a handler, and are not yet compensated. Only compensation handlers of scopes that are directly enclosed by the scope that contains the compensate activity will be executed. The handlers are executed in reverse order, so the handler of the last completed scope is executed first.
- Compensate activities can only be executed from catch blocks and compensation handlers.
- Compensation activities either trigger compensation for all enclosed and completed scopes using the compensate activity (supported in BPEL 1.1 and 2.0), or can trigger compensation for one specific scope using the compensateScope activity (only BPEL 2.0).
- Compensation handlers can only be defined on scope level, not on sequence level.
DemoThe demo consists of a SOA composite that implements a simplified Order-to-Cash process. The composite contains a single, asynchronous BPEL component called CompensationExample. After receiving the input message the process executes the following scopes and sequences:
- Scope Register_Order. This scope simulates the registration of the new order using an Empty activity called Dummy_Register_Order. The scope defines a compensation handler that simulates an undo activity by updating the order with a new status (e.g. cancelled).
- Scope Invoke_CreditCardService. This scope simulates the registration of the new order using an Empty activity called Dummy_Book_CreditCard. The scope defines a compensation handler that simulates an undo activity by charging the opposite amount to the credit card.
- Sequence Throw_Fault. This sequence is added for demonstration purposes and throws a fault in case "compensate" is passed as input to the SOA composite; otherwise the process will complete normally. The fault is caught by the Catch_All sequence.
- Sequence Catch_All. This sequence includes a Wait activity before triggering compensation using a Compensate activity. The wait enables you to inspect the process instance in Enterprise Manager before the compensation logic is executed. After the compensation is completed, the process will send a callback message to the client indicating a fault occurred for this process instance.
|Process flow of the Compensation Hello World example|
After the wait has finished the compensation handler of the Invoke_CreditCardService is executed. Finally, the compensation of the Register_Order scope is executed. Again, by including Wait activities you can inspect the sequence of events in Enterprise Manager.
The flow of events is shown in the following figures:
|Process instance after fault is thrown, but before compensation is triggered|
|Process instance after compensation is triggered and the compensation handler for the Invoke_CreditCard_Scope is completed. The compensation handler for the Register_Order scope is still active.|
|Process instance after all compensation handlers have been executed.|
|Process instance after compensation has finished and the callback message has been send to the client invoking the process.|