We are currently starting to broadcast events from one central applications to other possibly interested consumer applications, and we have different options among members of our team about how much we should put in our published messages.
The general idea/architecture is the following :
- In the producer application :
- the user interacts with some entities (Aggregate Roots in the DDD sense) that can be created/modified/deleted
- Based on what is happening, Domain Events are raised (ex : EntityXCreated, EntityYDeleted, EntityZTransferred etc ... i.e. not only CRUD, but mostly )
- Raised events are translated/converted into messages that we send to a RabbitMQ Exchange
- in RabbitMQ (we are using RabbitMQ but I believe the question is actually technology-independent):
- we define a queue for each consuming application
- bindings connect the exchange to the consumer queues (possibly with message filtering)
- In the consuming application(s)
- application consumes and process messages from its queue
Based on Enterprise Integration Patterns we are trying to define the Canonical format for our published messages, and are hesitating between 2 approaches :
Minimalist messages / event-store-ish : for each event published by the Domain Model, generate a message that contains only the parts of the Aggregate Root that are relevant (for instance, when an update is done, only publish information about the updated section of the aggregate root, more or less matching the process the end-user goes through when using our application)
Pros
- small message size
- very specialized message types
- close to the "Domain Events"
Cons
- problematic if delivery order is not guaranteed (i.e. what if Update message is received before Create message ? )
- consumers need to know which message types to subscribe to (possibly a big list / domain knowledge is needed)
- what if consumer state and producer state get out of sync ?
- how to handle new consumer that registers in the future, but does not have knowledge of all the past events
Fully-contained idempotent-ish messages : for each event published by the Domain Model, generate a message that contains a full snapshot of the Aggregate Root at that point in time, hence handling in reality only 2 kind of messages "Create or Update" and "Delete" (+metadata with more specific info if necessary)
Pros
- idempotent (declarative messages stating "this is what the truth is like, synchronize yourself however you can")
- lower number of message formats to maintain/handle
- allow to progressively correct synchronization errors of consumers
- consumer automagically handle new Domain Events as long as the resulting message follows canonical data model
Cons
- bigger message payload
- less pure
Would you recommend an approach over the other ?
Is there another approach we should consider ?