Implementing the Saga pattern on Azure - Part 2

In this post, we explore why traditional transactions are not well-suited to the emerging serverless paradigm. We also emphasize some valuable definitions and concepts.

What is a transaction ?

Transactions in relational databases are a fundamental concept, playing a pivotal role in highlighting the capabilities of these technologies. Developers have traditionally placed implicit trust in the internal mechanisms implemented by Oracle or SQL Server to guarantee data integrity and consistency.

1CREATE TABLE ValueTable (id INT);  
2BEGIN TRANSACTION;  
3   INSERT INTO ValueTable VALUES(1);  
4   INSERT INTO ValueTable VALUES(2);  
5COMMIT;

In the example provided, a table is created, and two insertions are attempted.

  • If one of these insertions fails, no rows will be present in the table.
  • Conversely, if both insertions succeed, the two rows will be present in the table.

This functionality is widely accepted, to the extent that the complexity behind this seemingly straightforward operation often goes unnoticed.

As long as traditional architectures were predominantly monolithic, characterized by a single codebase and a unified SQL repository, this wasn't a significant issue. Many successful applications were implemented without concerning themselves with these matters. However, with the advent of the microservices paradigm, some previously overlooked challenges have resurfaced and must now be addressed.

Indeed, consider a modern ecommerce platform designed with a microservices architecture in mind, delineating bounded contexts as illustrated in the figure below. What unfolds when a customer initiates an order ?

In this scenario, resorting to a traditional transaction is not feasible due to the involvement of two distinct datastores. The most straightforward course of action is to omit the transactional mechanism altogether.

Most of the time, it will function as expected (given that network issues are relatively uncommon). When an order is placed, it should appear in both datastores. However, consider a scenario where a problem arises just after the insertion into the Order database.

In such a scenario, the issue can be quite consequential: a record is inserted into the Order database, and the merchant includes it in their accounting. However, the customer will never receive their order, leading to all the potential consequences one can imagine.

Why is this problem arising now ?

In reality, this problem had never vanished; rather, it was concealed by the intricate machinery of existing databases. With the rise of distributed architectures and the myriad technologies involved, it can no longer be delegated and becomes a challenge for developers.

Who claimed that microservices were a simpler solution ? Like all engineering paradigms, it simplifies certain aspects but gives rise to other very acute consequences. Transactions are a byproduct of that.

Caution

It is more intricate than that. With the advent of NoSQL databases, such as document-oriented ones, it is not always feasible to span a transaction within the same datastore. For instance, CosmosDB only permits transactions within the same container (not across containers) and imposes severe limitations.

In the subsequent sections of this series, we will now introduce approaches to tackle this issue. Conventionally, these challenges, along with their solutions, are termed as patterns, and there is no exception here. Enter the Saga pattern.

Implementing the Saga pattern in C# - Part 3