Consider the following business requirements:
We have players which can play games. A player can play only one game at a time. A game needs two players.
The system will contain millions of players, and games take about two minutes. Concurrency issues are likely to emerge.
We want to comply to the rule that a single transaction involves a single aggregate. Further, eventual consistency must not lead to accepted games which must be cancelled afterwards (even if a short period of time) due to concurrency issues. Thus, eventual consistency is not really appropriate.
How do we need to define the aggregates and their boundaries to enforce these business rules?
I conceived two approaches:
1. Event-based handshake
Aggregate Player
, aggregate Game
.
When a game is requested, it pushed a GameRequested
-event. The Player
s subscribe this event and respond with a corresponding event, either GamePlayerAccepted
or GamePlayerRejected
. Only if both Player
s have accepted, the Game
starts (GameStarted
).
Pros:
- The aggregate
Player
is responsible for managing his own availability which corresponds to the domain model
Cons:
- The responsibility of starting a
Game
is scattered throughout multiple aggregates (it seems like "fake"-eventual-consistency) - Much communication overhead
- Consistency measures needed, e.g. freeing up the
Player
s if something went wrong
2. Collection-aggregate
Aggregate Player
, aggregate GamesManager
(with a collection of value-objects ActiveGamePlayers
), aggregate Game
.
The GameManager
is requested to start a new Game
with two given Player
s. The GameManager
is able to ensure that a Player
only plays once at a time since it's a single aggregate.
Pros:
- No consistency-enforcing events such as
GamePlayerAccepted
,GamePlayerRejected
and so forth
Cons:
- The domain model seems obscured
- The responsibility of the
Player
to manage availability shifted - We have to ensure that only one instance of
GameManager
is created and introduce domain-mechanisms which let the client not worry about the intermediary-aggregate - Independent
Game
-starts disrupt each other because theGameManager
-aggregate locks itself - Need for performance optimization since the
GameManager
-aggregate collects all active game players which will be tens of millions
It seems like none of these approaches are appropriate to solve the problem. I don't know how to set the boundaries to ensure both strict consistency and clarity of the model, and performance.