Compensating Transaction in Microservices

Javed Iqbal
CodeX
Published in
3 min readSep 1, 2021

What is a distributed transaction?

When a microservice architecture decomposes a monolithic system into self-encapsulated services, it can break transactions. This means a local transaction in the monolithic system is now distributed into multiple services that will be called in a sequence.

Here is a customer order example with a monolithic system using a local transaction:

In the customer order example above, if a user sends a Put Order action to a monolithic system, the system will create a local database transaction that works over multiple database tables. If any step fails, the transaction can roll back. This is known as ACID.

When we decompose this system, we created both the CustomerMicroserviceand the OrderMicroservice, which have separate databases. Here is a customer order example with microservices:

In monolithic application we have database system to ensure Acidity but the question is how to ensure atomic transaction in case of microservices application ?

In this model, a typical business operation consists of a series of separate steps. While these steps are being performed, the overall view of the system state might be inconsistent, but when the operation has completed and all of the steps have been executed the system should become consistent again. So in microservices the idea is to achieve eventual consistency .

A challenge in the eventual consistency model is how to handle a step that has failed. In this case it might be necessary to undo all of the work completed by the previous steps in the operation. However, the data can’t simply be rolled back because other concurrent instances of the application might have changed it. Even in cases where the data hasn’t been changed by a concurrent instance, undoing a step might not simply be a matter of restoring the original state.

Solution :

The solution is to implement a compensating transaction. The steps in a compensating transaction must undo the effects of the steps in the original operation. A compensating transaction might not be able to simply replace the current state with the state the system was in at the start of the operation because this approach could overwrite changes made by other concurrent instances of an application. Instead, it must be an intelligent process that takes into account any work done by concurrent instances.

Compensating transaction can be achieved by using SAGA design pattern .

The Saga pattern is another widely used pattern for distributed transactions. It is different from 2pc, which is synchronous. The Saga pattern is asynchronous and reactive. In a Saga pattern, the distributed transaction is fulfilled by asynchronous local transactions on all related microservices.

Here is a diagram of the Saga pattern for the customer order example:

In the example above, the OrderMicroservice receives a request to place an order. It first starts a local transaction to create an order and then emits an OrderCreated event. The CustomerMicroservice listens for this event and updates a customer fund once the event is received. If a deduction is successfully made from a fund, a CustomerFundUpdated event will then be emitted, which in this example means the end of the transaction.

If any microservice fails to complete its local transaction, the other microservices will run compensation transactions to rollback the changes. Here is a diagram of the Saga pattern for a compensation transaction:

In the above example, the UpdateCustomerFund failed for some reason and it then emitted a CustomerFundUpdateFailed event. The OrderMicroservice listens for the event and start its compensation transaction to revert the order that was created.

--

--

Javed Iqbal
CodeX
Writer for

Backend Developer, Java , Spring Stack , Spark, Kafka, Python