Because the idea of the Enode framework is that a single modification can only create a new or modified aggregate root; What if a user requests a new or modified item that involves more than one aggregation root? The purpose of this paper is to analyze how the problem is solved under the Enode framework. If you want to directly by looking at the code friend, you can directly download the source code, a total of three examples in the source, Banktransfersagasample This example is the example used in this article.
The origin of Saga
Saga this term, perhaps many people are still unfamiliar. Saga was first proposed to solve the problem of a distributed transaction (long-running process) that may run for a long time. The so-called long-running distributed transactions, refers to those enterprise business processes, the need to cross application, across the enterprise to complete a transaction, even in the transaction process also requires manual involvement, such transactions can be completed in minutes, in hours, or even days. This type of transaction, if designed according to the acid requirements of the transaction, is bound to result in a significant reduction in the availability of the system. Imagine a transaction involving two servers, server A initiates a transaction, Server B participates in the transaction, and B's transactions require human involvement, so the processing time can be very long. If the principle of acid is to maintain the isolation and consistency of the transaction, the transaction resource used in the transaction initiated in server A will be locked and no other application is allowed to access intermediate results in the transaction until the entire transaction is committed or rolled back. This causes the resources in transaction A to be locked for a long time and the availability of the system is unacceptable.
Saga, then, is a message-driven solution based on compensation for solving long-running process. The goal is to ensure data consistency as much as possible while ensuring that the system is highly available. Or the example above, if implemented with Saga, that is the process: Server A's transactions are executed first, and if the execution is successful, then transaction A is committed, and if the commit succeeds, then transaction B is executed, and if transaction B is performed smoothly, then transaction B is committed and the entire transaction is completed. However, if transaction B fails, the transaction B itself needs to be rolled back, and because transaction A is committed, a compensation operation is required to reverse the action performed by the committed transaction A and revert to the state of transaction A before it is executed. Such a message-driven approach to implementation is saga. We can see that saga is sacrificing the strong consistency of data, only achieve the final consistency, but improve the overall availability of the system.
Saga under the CQRS architecture (process Manager)
The above paragraph, we know the origin of Saga, now we look at the CQRS architecture, Saga is used to do what. Although it is called Saga, in fact, in the CQRS architecture, people often use saga to solve the problem of communication between multiple aggregations or multiple bounded context in DDD. There is a concept of bounded context in DDD. A bounded context represents a contextual boundary that may contain one or more aggregations in a bounded. And saga is used to achieve communication between bounded context, or between aggregation. In classical ddd, we usually use Domain Services to achieve multiple aggregation coordination, and ultimately to submit all the changes to the aggregation through a transactional approach; The consequence is that 1: the transaction is used; 2. A transaction involves a change of multiple aggregations; it's OK to do so, if the conditions allow (for example, not to appear In the case of a distributed transaction or a low number of concurrent modified requests, there is no particular problem. The only problem is that doing so increases the likelihood of concurrent conflicts. Today's Web applications, often multiple users at the same time to the system to send a variety of processing requests, so it is not difficult to think that a transaction involving more aggregation, the likelihood of concurrent conflict is higher. Not only that, if your aggregation is large, contains a lot of child entities and a lot of methods, the probability of concurrent conflicts when the aggregation is persisted is also relatively high, and the concurrency conflict of the system will directly affect the usability of the system; Therefore, the general suggestion is that we should try to design the aggregation as small as possible, and try to modify only one aggregation at a time. So that we don't need a business, it also minimizes the likelihood of concurrent conflicts; Of course, there are concurrent conflicts when a single aggregation is persisted, but this is relatively easy to solve, because a single aggregation is the smallest unit of data consistency, so we can solve the problem of concurrent coverage with no transaction at all, with optimistic locking Discussion on this issue, if you still have interest or want to understand more in-depth, I recommend to see effective Aggregate design This paper, a total of three parts, the author is "Implementing Domain-driven design" a The author of the book.
So, through the above analysis, we know that "aggregation should be designed small, and once modified to modify only one aggregation," such an unwritten principle. Of course you have a lot of reasons to think that should not be so, welcome to discuss. So if you follow this principle, then we need a mechanism to solve the problem of communication between multiple aggregations. In the CQRS architecture, people also call this mechanism saga, but because the saga semantics of this CQRS architecture are not the saga described in the preceding paragraph. So, Microsoft also called the CQRS under the framework of the saga Process Manager, you can look at Microsoft a CQRS architecture of the Open source project example; The name of process manager should be easy to understand, that is, the process manager. In fact, what a saga does is the same thing as a process. But the traditional process, there is a process definition, when the user initiates a process, it will produce a process instance, the process example will be strictly in accordance with the flow of process definition flow, driving the flow of the process is often people's operations, such as approval operations. Process Manager is also a process, except that the process is driven by messages. A typical process manager responds to an event and then produces a new command to perform the next action. People who have used nservicebus should know that the saga mechanism is built into nservicebus, we can easily use it to implement distributed message-driven long-running process;