How to model an unbounded collection of child aggregates

Hello together,

I am currently working on a project which includes the concept of events that happen according to a recurrence rule. Users can define a series of events that start on a date and take place according to the recurrence rule (potentially without a limit so no end date).

Since it is not practical to “generate” all events in a database we generate the events whenever they are requested. Our current model has two aggregates:

The aggregate EventSeries includes

  • a template for the events like a name, time, duration, and so on
  • a start/end date
  • the recurrence rule

The second aggregate is Event. This aggregate is only created if an exception is created for an event series. For example, the event series states that dinner happens every day at 6 pm but on a single occasion dinner is delayed by one hour.

I envision the logic to be somewhere along the lines of:

  • User edits a single event
  • some component checks whether an event aggregate already exists
  • if yes: sends an EditEventCommand to the event
  • if no: sends a CreateEventSeriesExceptionCommand to the event series and after successful completion the EditEventCommand to the newly created event

I guess a saga would fit in case the exception is not created. The check of whether the event exception already exists could be performed like a set-based validation in an external command handler that dispatches the correct follow-up command.

Does this sound like a reasonable solution or is there a better option? I just came up with this design while writing this post. Writing things down does help sometimes I guess :sweat_smile:

Best regards

Hi Daniel, any updates on the design? It does seem like having long running aggregates/saga’s with deadlines is a way to do it with Axon. In this case I’m not sure through how it might scale if there are a lot of Users. So I would at least do a load test to figure out the limit of the amount of users.

Hi @Gerard, I came up with a solution that is close to the one I outlined in my initial post.

I saw that I can directly access a repository for an aggregate. This allows me to define an external command handler for all commands which could lead to an event series exception. Let’s use the feature “Update event description” as an example.

To model this in Axon, I introduce the commands RequestUpdateEventDescription and UpdateEventDescription.

The RequestUpdateEventDescription command is handled by an external command handler. This handler checks whether an event series exception is already created. If yes, the UpdateEventDescription command is sent to the Event aggregate. If not, the external command handler sends a command to the Event Series which creates an event exception as a child aggregate. After that, the UpdateEventDescription command is sent to the newly created aggregate. This process uses the repositories of the Event and Event Series aggregates to retrieve the right aggregates in the external command handler.

The checks inside the external command handler use a command model which is built up from the events that are emitted whenever an event exception is created. I use subscribing event handlers on the command side for this as it is pretty much the same as set-based validation.

I am still keen on getting some feedback from experienced Axon engineers on whether this is a viable approach. From what I have tested so far the solution feels quite nice, maintainable, and extensible. The only downside I see is that I need to create two commands for each edit request. However, I have seen this pattern quite often so I guess this is common practice anyways.