i wonder what is the correct solution to ensuring consistency of a shared aggregate?

Problem statement

I try to model the registration at an event with reserved (and limited) seats (like shopping cart) that expires after n minutes when not confirmed by the applicant (like checkout). If all seats are gone, the user is added to a waiting list. In order not to repeatedly update a counter of how many seats are currently available when determining the registration request status I count requests having status=reserved and status=confirmed AND waiting_list=true where expirationDate > Time.Now() and subtract that value from a quota (attached to that role), that indicates how many seats (of that role) are available. Only when a request gets confirmed, I decrease the quota and set status = confirmed.

This has the advantage that I don't need to explicitly update requests when they expire, because i can just filter them out in SQL (WHERE expirationDate > NOW())


I modelled the problem as follows (entities/aggregates in bold):

  • An event registration has registration requests (request from now on)
  • An Applicant can issue a request at an event registration with a role
  • A role has 0..N quotas, that indicate how many "seats" of that role are left (all quota.available must be >0 when applicant wants to register, imagine role "VIP" connected to quota "MaxNumberVIP'S" and "MaxEventParticipants", user can only register when there is a free slot in both quotas).
  • A request has a status that indicates its validity (reserved, confirmed). a expirationDate and a flag if the request is on the waitingList or not.

Note that when a reserved slot expires, the slot is not available again, the first applicant on the waitinglist would take the seat instead.

Now, when a applicant issues a registration request with a role at a registration the request is created as follows:

request.isOnWaitingList = getAvailableSlots() == 0 

getAvailableSlots(): // pseudo code
return role.Quota.Available - allRequests.Where(status == reserved) + allRequests.Where(status == confirmed).And(isOnWaitingList == true)

When a user issues a registration request, the following results occur, depending on current requests (for a single role):

Example 1 (0 slots free: 3-2-1=0):
QuotaFree: 3
Reserved: 2
Waitinglist: 1
=> status: reserved, waitinglist=true

Example 2: (1 slot free)
QuotaFree: 2
Reserved: 1
Waitinglist: 0
=> status: reserved; waitinglist=false

The Problem

The Problem now is, that the Entity RegistrationRequest needs the quota of a role in oder to determine the status of a new request, however if a request gets confirmed, the quota is written by a RegistrationRequestConfirmation entity, therefore it can't be part of both aggregates at the same time, otherwise transactional consistency would be violated. How can i model this accordingly? Quota is needed by both aggregates and thats my frustration here.


  • Why are these two different aggregates? They seem to be states. Oct 4, 2020 at 18:14
  • You might want to revise the way you consider this too. As is see it everyone is added to the waiting list. From the waiting list people are made time limited offers. If they reject, or the time expires the offer is made to the next suitable request on the waiting list. If that next suitable person isn't the top of the list, then perhaps a suitable wait occurs to see if more quota becomes available from cancellation/rejection/timeout to make that person happy, before moving down the list.
    – Kain0_0
    Oct 5, 2020 at 2:31
  • 1
    You seem to be confused about the difference between aggregates and entities. Your question reads as if you think they're the same thing, but they're not. Imo this problem is easily solved by creating a single AggregateRoot EventRegistration that contains both requests and confirmations and other entities or value objects to fullfill the desired behavior.
    – Rik D
    Oct 5, 2020 at 9:00


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.