From command to event
A successful command can produce events. Persist them only if the stream still has the version used to make the decision.
The write path
Receive the command, load the aggregate, invoke its behavior, and append the resulting events with an expected version.
Do not record a successful external operation before it has succeeded. For example, requesting payment and recording payment authorization are different steps.
Optimistic concurrency
If another append has changed the stream version, the write is rejected. Reload the aggregate and re-evaluate the command, or report the conflict.
The version check detects a conflicting write. Domain invariants determine whether the command is valid against the new state.
Idempotency
A timeout does not tell the client whether an append committed. Retry the same append with the same idempotency key and payload according to the API contract.
Append idempotency is not the same as command idempotency. A command handler must also account for repeated business requests and external side effects.
Common errors
Do not make a domain decision from a lagging read model when it requires current aggregate state. Do not omit the expected version merely to avoid conflicts.
Do not rerun command handling during event replay. Reconstructing recorded state and deciding on a new command are separate operations.
Practical exercise
Handle two commands against the same loaded version. Verify that only one conflicting append succeeds, then reload and decide how the other command should be handled.
Event Sourcing learning path · Previous · Next · Chronacta documentation
