Implementing Complex Distributed (Business) Transactions with Saga Pattern (and workflows)

I talked about microservices at two conferences last week. In both opportunities, the attendees asked me about how to implement the Saga pattern. So, I decided to blog about it.

What is a Saga?

From the microservices.io:

A saga is a sequence of local transactions. Each local transaction updates the state (database) and publishes a message or event to trigger the next local transaction in the saga. If a local transaction fails because it violates a business rule then the saga executes a series of compensating transactions that undo the changes that were made by the preceding local transactions.

The original idea is pretty old and comes from this article.

The implementation I recommend is known as “Orchestration-based saga.”

Saga as a Flow

I like to think Sagas as a long-running flow. Using BPMN (Business Process Modeling Notation), we could represent the preceding Saga as follows:

 

The good thing about representing Sagas as workflows is that we can run it using a workflow engine. So the workflow engine can act as the Saga Execution Coordinator.

What workflow engine I should/could use?

Like everything, the correct answer is: “It depends.” There are several options you could use. Some options are potent (and expensive). Also, there are a lot of lightweight and cheap alternatives. The right choice depends on your project.

I have been working (a lot) in a lightweight workflow engine library that you could use in your projects to solve a lot of problems (including “how to implement Sagas,” of course). It is still under development, but it will be ready to use soon.

Here is a preview of how you would configure your saga using my library:

var model = ProcessModel.Create()
  .AddEventCatcher<CreateNewOrderCommand>("start")
  .AddActivity<CreateOrderActivity>("CreateOrder")
  .AddActivity<CancelOrderActitivity>("CancelOrder")
  .AttachAsCompensationActivity("CancelOrder", "CreateOrder")
  .AddActivity<CreateOrderActivity>("ReserveProducts")
  .AddActivity<CancelOrderAcitivity>("CancelReservation")
  .AttachAsCompensationActivity("ReserveProducts", "CancelReservation")
  .AddActivity<RequestPaymentActivity>("RequestPayment")
  .AddActivity<CancelPaymentActivity>("CancelPayment")
  .AttachAsCompensationActivity("RequestPayment", "CancelPayment")
  .AddActivity<RequestDeliveryActivity>("RequestDelivery")
  .AddEventThrower("end")
  .AddSequenceFlow("start", 
  "CreateOrder", "ReserveProducts", 
  "RequestPayment", "RequestDelivery",
  "end"
  );

var models = new InMemoryProcessModelsStore(model);
var instances = new InMemoryProcessInstancesStore();

var manager = new ProcessManager(models, instances);

Nice, huh?

Let me know if you are implementing microservices and need help. It would be a pleasure to help your company. Also, I would love to help you to start using my library (again, it is under development and source code is on Github).

Compartilhe este insight:

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Há tempos que percebo em mim a ocorrência de um padrão recorrente. Não acho que ele seja exclusividade minha, mas,...
In this post, I will show how to do your first steps with OpenCV quickly using Visual Studio 2017 and...
Outro dia, meu amigo Giovanni Bassi compartilhou o seguinte tuíte: Ele e eu concordamos em discordar muitas vezes. Esta é...
Publicado originalmente no meu blog em 2011 (infelizmente, este conteúdo não está mais disponível). Também publiquei no Linkedin. A publicação...
In a previous post, I started an elementary search library using C#. Now, I will improve it adding a Porter...
As a consultant, I often need to work with the code that I do not know. I need to understand...