Problem:
Two employees (A & B) go off-line at the same time while editing customer #123, say version #20, and while off-line continue making changes...
Scenarios:
1 - The two employees edit customer #123 and make changes to one or more identical attributes.
2 - The two employees edit customer #123 but DO NOT make the same changes (they cross each other without touching).
... they then both come back on-line, first employee A appends, thereby changing the customer to version #21, then employee B, still on version #20
Questions:
Who's changes do we keep in scenario 1?
Can we do a merge in scenario 2, how?
Context:
1 - CQRS + Event Sourcing style system
2 - Use Event Sourcing Db as a Queue
3 - Eventual Consistency on Read Model
4 - RESTful APIs
EDIT-1: Clarifications based on the answers so far:
In order to perform fined grained merging, I'll need to have one command for each of field in a form for example?
Above, finely grained commands for ChangeName, ChangeSupplier, ChangeDescription, etc., each with their own timestamp would allow for auto-merging in the event A & B both updated ChangedName?
Edit-2: Follow up based on the the use of a particular event store:
It seems as though I'll make use of @GetEventStore for the persistence of my event streams.
They make use of Optimistic Concurrency as follows:
Each event in a stream increments stream version by 1
Writes can specify an expected version, making use of the ES-ExpectedVersion header on writers
-1 specifies stream should not already exist
0 and above specifies a stream version
Writes will fail if the stream is not at the version, you either retry with a new expected version number or you reprocessed the behavior and decided it's OK if you so choose.
If no ES-Expected Version specified, optimistic concurrency control is disabled
In this context, the Optimistic Concurrency is not only based on the Message ID, but also on the Event #
CQRS is implemented by a separation of responsibilities between commands and queries, and event sourcing is implemented by using the sequence of events to track changes in data.
It's always in-sync. CQRS is rarely synchronous because we want to work/scale with different resources, type of databases, use a messaging infrastructure: we can rarely make a distributed transaction cross-resources (we could talk about XA or Sagas but… not now!).
One of the most popular practices in event-driven architectures today is called CQRS, which is short for Command Query Responsibility Segregation. CQRS is a style of architecture that allows you to use different models to update and read domain data.
CQRS is a popular architecture pattern because it addresses a common problem to most enterprise applications. Separating write behavior from read behavior, which the essence of the CQRS architectural pattern, provides stability and scalability to enterprise applications while also improving overall performance.
If I understand your design picture correctly, then the occasionally connected users enqueue commands, i.e., change requests, and when the user reconnects the queued commands are sent together; there is only one database authority (that the command handlers query to load the most recent versions of their aggretates); only the view model is synced to the clients.
In this setup, Scenario 2 is trivially auto-merged by your design, if you choose your commands wisely, read: make them fine-grained: For every possible change, choose one command. Then, on re-connection of the client, the commands are processed in any order, but since they only affect disjunct fields, there is no problem:
ChangeName
command, the Customer of v20 is loaded and persisted as v21.ChangeAddress
command, the Customer of v21 is loaded and persisted as v22.In Scenario 1, with this setup, both employees will overwrite the other employees' changes:
ChangeName
command to "John Doe", the Customer of v20 is loaded and persisted as v21 with name "John Doe"ChangeName
command to "Joan d'Arc", the Customer of v21 (named "John Doe") is loaded and persisted as v22 (with name "Joan d'Arc').If B comes online before A, then it's vice versa:
ChangeName
command to "Joan d'Arc", the Customer of v20 is loaded and persisted as v21 (with name "Joan d'Arc').ChangeName
command to "John Doe", the Customer of v21 is loaded and persisted as v22 with name "John Doe".There are two ways to enable conflict detection:
Customer
. This will disable the auto-merge feature of Scenario 2, but will give you full conflict detection against concurrent edits.Customer
it is going to change. This will leave the auto-merge of Scenario 2 intact, but will give you auto-conflict-detection in Scenario 1.Both are easy to implement with event sourcing (since the timestamps of the individual events in the event stream are probably known).
As for your question "Who's changes do we keep in scenario 1?" -- this depends on your business domain and its requirements.
EDIT-1: To answer on the clarification question:
Yes, you'll need one command for each field (or group of fields, respectively) that can be changed individually.
Regarding your mockup: What you are showing is a typical "CRUD" UI, i.e., multiple form fields and, e.g., one "Save" button. CQRS is usually and naturally combined with a "task based" UI, where there would be, say, the Status
field be displayed (read-only), and if a user wants to change the status, one clicks, say, a "Change Status" button, which opens a dialog/new window or other UI element, where one can change the status (in web based systems, in-place-editing is also common). If you are doing a "task based" UI, where each task only affects a small subset of all fields, then finely grained commands for ChangeName, ChangeSupplier etc are a natural fit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With