Distributed Transaction — Implementation using REDIS and NodeJS

Sukitha Jayasinghe
Nerd For Tech

--

The distributed transaction implementation has become one of the biggest challenges in microservice development due to its distributed nature. There are some well-known patterns available to address this problem. In this article, I am going to explain a sample implementation done using Redis and Nodejs. First of all, let's discuss the background of the problem which we are going to solve.

In design, RDBMS systems support ACID transactions. Transactions revert themselves if any statement gets failed. The Microservice model doesn't support this because of the dedicated datastore available for service. Most of these datastores behave according to the BASE properties. You can read more about ACID vs BASE from this article (Link).

It is important to understand a complete ACID transaction is not possible in the microservice model. Hence your distributed transaction implementation is highly subjective to the problem domain and expectation of the system. I have made some assumptions when implementing this sample.

Let's see the component design of the solution first.

Successful Transaction

Components

  • REST Service
  • Order Service
  • Payment Service
  • Delivery Service
  • Status Service

REST Service

The REST service is the entry point. It accepts and validates the request before generating an id for the transaction. The generated id returns to the client in the http response. Validated request forwards to the ORDER: QUEUE for further processing.

REST Service Request and Response

Data get stored in an Eventual consistent manner so anytime we can replay the transaction and do manual or batch reconciliation on failure.

Post Request to create an Order
Get Request to Poll the transaction status

Order Service/Payment/Delivery Services

Each Service reads the request, processes it further, and embeds additional details such as cost. Then forwards the event to the next queue. The reconciliation process is also implemented in the same service. So the responsibility of reversing the transaction is given to the relevant service.

Recovery

Let's look at the reconciliation process.

The diagram shows how the recovery process gets executed when the payment operation fails. I have simulated this by setting item id 200 as a failure case. In this scenario, the payment service informs the Order service to revert the transaction. Order service changes the soft status to failure. The front end can see that transaction failed. There are some best practices when designing reversing transactions. The reverse process should be simple and it shouldn't fail easily. Irreversible steps such as send SMS should execute at end of the transaction.

Conclution

The implementation done in this article is very simple. The actual problem domains are much more complex and may involve dozens of services and hundreds of events. But the basic concepts remain the same. There are lots of technologies and concepts that can help to solve similar issues (Link).

I have used Redis as the queue in this sample. But, Kafka might be a better queue selection for production as we can use Kafka ack to implement application-level fault tolerance, Kafka Connect with Debezium as CDC solution and Kafka itself as the event sourcing database.

--

--

Sukitha Jayasinghe
Nerd For Tech

Software Architect with 10+ years experience designing and developing enterprise and cloud applications