Compensating Service Transaction pattern helps consistently handle composition runtime exceptions while eliminating the need for locking resources.
Service compositions could generate various runtime exceptions as part of fulfilling service functionality. For example, imagine a service composition that invokes a decision service to validate request data, proceeds to update a customer entity via an entity service, and then sends a message on a queue for an external process to consume. Consider the three steps as part of a single unit of work – a service transaction that execute in sequence.
If runtime exceptions associated with the composition are unhandled there is an increased likelihood of compromising data and business integrity. Similarly, if all the steps are executed as an atomic transaction each service invocation will tie up backend resources (e.g. using various kinds of locks) hurting performance and scalability.
The compensating service transaction pattern introduces additional compensation steps in order to handle runtime exceptions without locking system resources. These additional steps can be included as part of the composition logic or made available as separate undo service capabilities. Continuing the earlier example, a call to undo the customer update (essentially resetting the data back to the earlier state) can be made to place the underlying data in a valid state.
The Compensating Service Transaction pattern provides several benefits:
- Eliminates the need for executing distributed service invocations within a transactional context.
- Provides a mechanism for services/resources that don’t support atomic transactions to participate in service compositions.
- Reduces load on underlying systems and databases by only invoking compensation routines when failure occurs. Instead of locking resources in case failures happen, the idea is to handle runtime exceptions when they actually occur.
- Allows reuse of compensation steps across service compositions. E.g. two business services that update a data entity can reuse the undo Update capability.
Compensating transactions tend to be more open-ended when compared to atomic transactions and their actual effectiveness varies. The extent to which the service composition can apply this pattern is directly dependent on the undo capabilities provided by various service capabilities being invoked. Consequently, this pattern cannot be leveraged if compensating transactions don’t exist. Likewise, it is necessary to ensure that the compensating steps themselves execute successfully. Error alerts/notifications may need to be sent in case compensations fail and manual interventions are needed.