Compensation
Compensation in Workflows is the mechanism by which previously completed work can be undone or compensated (following the logic defined by the application) when a subsequent failure occurs. CompensableActivity allows a developer to specify a Body activity that defines a long-running task that performs their core business logic. It also allows the developer to optionally specify a compensation and confirmation activity to schedule appropriate business logic in the event of errors or successful completion of the Body.
For an example of how the CompensableActivity can be used, download the sample file at iCIS examples.
Compensation vs. Transactions
A transaction allows you to combine multiple operations into a single unit of work. Using a transaction gives your application the ability to abort (roll back) all changes executed from within the transaction if any errors occur during any part of the transaction process. However, using transactions requires support from the facility at which the work is done, for example a database server. Many actions that may be performed do not support transactions, for example file system access and FTP connections. Transactions may also not be appropriate if the work is long running. In scenarios such as this compensation can be used to undo previously completed work if there is a failure at a later stage in the Workflow.
Using CompensableActivity
CompensableActivity is the core compensation activity in Workflows. Any activities that perform work that may need to be compensated are placed into the Body of a CompensableActivity. In the example below a CompensableActivity is placed in a ForEach loop iterating over a list of filenames. The Body of the CompensableActivity renames a single file to a temporary name for processing and processes that file. In the CompensationHandler the rename is undone by renaming the file back to its original name, while the ConfirmationHandler deletes the temporary file since we are then done by the processing. If an error occurs during processing of one of these files, an exception is thrown causing the Workflow to be canceled. This in turn will schedule the activities in the CompensationHandler for all CompensableActivity instances whose Body was successfully completed, meaning that all files that were renamed will be renamed back.
In a real-world scenario the cancellation handler would need to include code to undo any actions of the Body that were already executed when the cancellation occurred, but that is omitted here for the sake of brevity.
Default Workflow Compensation
By default, if the Workflow is canceled, either due to the system being shut down or an unhandled exception occurs, the compensation logic is run for any compensable activity that has successfully completed and has not already been confirmed or compensated.
When a CompensableActivity is confirmed, compensation for the activity can no longer be invoked. The confirmation process is described later in this section.
Cancellation and CompensableActivity
If the activities in the Body of a CompensableActivity have not completed and the activity is canceled, the activities in the CancellationHandler are executed.
The CancellationHandler is only invoked if the activities in the Body of
the CompensableActivity have not completed and the activity is canceled.
The CompensationHandler is only executed if the activities in the Body
of the CompensableActivity have successfully completed and compensation
is subsequently invoked on the activity.
The CancellationHandler gives Workflow authors the opportunity to
provide any appropriate cancellation logic.
Explicit Compensation Using the Compensate Activity
In the previous section, implicit compensation was covered. Implicit compensation can be appropriate for simple scenarios, but if more explicit control is required over the scheduling of compensation handling then the Compensate activity can be used. To initiate the compensation process with the Compensate activity, the CompensationToken of the CompensableActivity for which compensation is desired is used. The Compensate activity can be used to initiate compensation on any completed CompensableActivity that has not been confirmed or compensated. For example, a Compensate activity could be used in the Catches section of a TryCatch activity, or any time after the CompensableActivity has completed. In this example, the Compensate activity is used in the Catches section of a TryCatch activity to reverse the action of the CompensableActivity.
Confirming Compensation
By default, compensable activities can be compensated any time after they have completed. In some scenarios this may not be appropriate. Confirming the compensable activity invokes the activity specified by the ConfirmationHandler. One possible use for this is to allow any resources that are necessary to perform the compensation to be released. After a compensable activity is confirmed it is not possible for it to be compensated, and if this is attempted an InvalidOperationException exception is thrown. When a Workflow completes successfully, all non-confirmed and non-compensated compensable activities that completed successfully are confirmed in reverse order of completion. To confirm a CompensableActivity, use the Confirm activity and specify the CompensationToken of the CompensableActivity to confirm.
Nesting Compensation Activities
A CompensableActivity can be placed into the Body section of another CompensableActivity. A CompensableActivity may not be placed into a handler of another CompensableActivity. It is the responsibility of a parent CompensableActivity to ensure that when it is canceled, confirmed, or compensated, all child compensable activities that have completed successfully and have not already been confirmed or compensated must be confirmed or compensated before the parent completes cancellation, confirmation, or compensation. If this is not modeled explicitly the parent CompensableActivity will implicitly compensate child compensable activities if the parent received the cancel or compensate signal. If the parent received the confirm signal the parent will implicitly confirm child compensable activities. If the logic to handle cancellation, confirmation, or compensation is explicitly modeled in the handler of the parent CompensableActivity, any child not explicitly handled will be implicitly confirmed.
For more information, see Compensation Programming Model.
Quick reference
Below is a summary of conditions required for each section of the CompensableActivity to execute.
Section | Conditions for execution |
---|---|
Body | When the CompensableActivity starts executing. |
CompensationHandler | When the Body of the CompensableActivity has completed successfully. and The ConfirmationHandler or the ConfirmationHandler has not executed and The Workflow is canceled or the CompensableActivity is explicitly compensated. |
ConfirmationHandler | When the Body of the CompensableActivity has completed successfully. and The ConfirmationHandler or the ConfirmationHandler has not executed and The Workflow completes successfully or the CompensableActivity is explicitly confirmed. |
CancellationHandler | When the Body of the CompensableActivity is canceled, either due to a system shutdown or an unhandled exception is thrown. |