If you commonly need to update multiple aggregates, your aggregate boundaries might be wrong.
Of course, there can be scenarios, in which multiple aggregates do need to be updated. A saga is the typical way to deal with this. Note, however, that you are working across consistency boundaries here.
If you have the need to update multiple aggregates atomically, it's very likely that you have to rethink your boundaries.
Your chat application is a perfect example to show how this can be very easy (if possibly counter-intuitive sometimes), as well as quite involved.
Let's say you have a simple requirement: a user cannot be in the same room twice.
One option is to make the
Room your aggragate, to which you can apply commands like
PostMessage, etc. The
Room will be responsible for enforcing the invariant.
Another option is to have a
Chatter aggregate (essentially the user). Again, you have commands like
JoinRoom and the
Chatter enforces the invariant.
Which layout you use depends on which other invariants you want to enforce.
Room approach allows you specify restrictions between actions in the same room (e.g. no more than 20 users can be in a room).
Chatter approach allows you to specify restrictions of your user, possibly regarding multiple rooms (e.g. a user can only be in one room at a time).
Where it becomes tricky is if you want some combination of those restrictions. If you can't find a way to slice your aggregates accordingly (without creating some kind of singleton-super-aggregate that encompasses your entire application), you may be able to work around this with a saga.
In this scenario, adding the concept of a
Session might be the right move. After the session is created, your saga tries to register it with the
Room aggregates (and kills the session if either one fails).
I would still spend some time trying to see if there's another (perhaps non-obvious) way to slice the aggregates first. Remember that they don't have to mirror your read-models: if you don't have any consistency constraints that apply to a whole room, you may not need a
Room aggregate on the command side at all.