user11033188
user11033188

Reputation:

Handling Eventual Consistency fail between aggregates

I am a beginner in DDD and I came across a situation that involves a rule of not modifying more than 1 aggregate in the same transaction, using Domain Events to resolve changes in other aggregates. (see Effective Aggregate Project).

The situation is as follows: The user schedules to transfer a patient to another hospital. When the transfer time comes, the user selects it in a list and clicks 'Start'. However, this action changes three aggregates:

Transfer: marked as started. ex: transfer.Start();

Patient: is marked as being transferred. ex: patient.MarkAsInTransfer();

Hospital: you must reserve a place for the patient who is now coming. ex: hospita;.ReservePlace(patient);

Thus, when transfer starts, it raise an event TransferStarted.

But, for some reason, when the transfer is already occurring, an error occurs when handling the TransferStarted event (changing the patient's status or reserving a place in destination hospital).

How to deal with this situation, since the patient is already in transfer? I need to forget and use transactional consistency, modifying three aggregates in the same transaction? Using a Domain Service to do it?

Remembering that I am following an aggregate transaction rule.

Upvotes: 1

Views: 744

Answers (2)

Francesc Castells
Francesc Castells

Reputation: 2857

When I face this sort of issue, the first thing I ask myself is: "are my aggregates correct, and do they have the right responsibilities"? After all, an aggregate is a transaction boundary which encapsulates the data and the business logic for a given process. If a process needs 3 aggregates, is it possible that they are, in fact, a single aggregate?

In your particular case, a Transfer sounds like an aggregate to me (as in, there must be some business rules to enforce and some data related to it), but Hospital and Patient look suspicious to me. What kind of data and business logic do they encapsulate and are in charge of? It obviously depends on the bounded context these aggregates are in, but it's something I would double-check. I assume though that they are all in the same BC.

For example, I would consider: why does a Patient need to be marked as in transfer? what kind of business rule does it enforce? If the reason is to avoid a Patient being transferred more than once, then it shouldn't be the listening an event from the Transfer (where does the transfer come from?), instead, it should be the one creating transfers (see Udi Dahan's Don't create aggregate roots). So, if you want to transfer a Patient, do Patient.TransferTo(otherHospital), which will check if the conditions are met to initiate a transfer and, if they are, send a Command to create a transfer. The Patient then can listen to TransferStarted, TransferCancelled, TransferCompleted events to update its own state safely (as a new transfer won't start until the previous one is completed either successfully or not).

From this point, the Hospital Room allocation would be something between the Transfer and the Hospital and the Patient doesn't need to know anything about it.

But regarding the Hospital, I don't know at this point, because it doesn't seem right to me that a single aggregate manages the room allocations of a whole Hospital. It seems a lot of data and responsibility and also, it's not clear to me that there's the need for transactionality: why the allocation of Patient A in Room 100 has to be transactional with the allocation of Patient B in Room 210? If you imagine the full Hospital, that's a lot of rooms and patients and a lot of contingency in a single aggregate, which won't allow concurrent changes. Obviously, I don't have enough knowledge of the domain and details to make a suggestion, these are only considerations.

Upvotes: 0

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57397

How to deal with this situation, since the patient is already in transfer? I need to forget and use transactional consistency, modifying three aggregates in the same transaction? Using a Domain Service to do it?

There are a couple of aspects to what's going on here.

1) From your description, you are dealing with entities out in the real world; the book of record for the real world is the real world, not your domain model. So when you receive a "domain event" from the real world, you need to treat it appropriately.

2) collaborative domains, with contributions from multiple resources out in the real world, are inherently "eventually consistent". The people over here don't know what's going on over there, and vice versa -- they can only act on the information they have locally, and report faithfully what they are doing.

What this means, in practice, is that you need to be thinking about your "aggregates" as bookkeeping about what's going on in the real world, and documenting actions that conflict with policy as they occur (sometimes referred to as "exception reports").

3) Often in the case of collaborative processes, the "aggregate" is the instance of the process itself, rather than the entities participating in it.

How to deal with this situation, since the patient is already in transfer?

You invoke the contingency protocol provided to you by the domain experts.

A way to think of it is to imagine a bunch of SMS messages going around. You get a message from the attending announcing that the transfer is starting, and the moments later you get a message from the destination hospital that it is in lockdown.

Now what?

Well, I'm not sure - it isn't my domain. But it's probably something like sending a message to the attending to announce that the destination has been closed.

The important things to notice here are that (a) conflicting things happening in different places is a property of distributed collaborative systems, and you have to plan for it -- the race conditions are real and (b) the information you have about the state of affairs anywhere else is always stale, and subject to revision.

Take a careful read of Data on the Outside versus Data on the Inside. The real world is outside, all of the information you have about it is stale. Also, review Memories, Guesses, and Apologies.

Upvotes: 1

Related Questions