Types of Messages and Events in Reactive CQRS World
In the previous article I've started pondering about CQRS from the perspective of Reactive Extensions and almost-infinitely scalable systems. Let's continue by formalizing types of messages and events available in this environment.
These building blocks are affected by the Reactive world, Domain Driven Design with Event Sourcing and Partitioning for the scalability.
NB: dear reader, if you are reading this article far in the future (i.e.: after September, 2010), keep in mind that views expressed here might already be outdated. In this case CQRS section will have something more late and solid to point you towards.
Command Message (D for Do) has following features:
- It is a message that instructs specific entity (identified by it's identity) to perform certain actions.
- Messaging infrastructure is aware of this command's identity and uses it to route command to the specific partition.
- Command message is an entity itself - it has an identity. This allows the recipient to stay idempotent and filter out seemingly similar commands that were duplicated by the messaging infrastructure.
- This message contains contains one or more entity commands. All entity commands in the same message are directed to the entity. They are expected to fail or succeed together (essentially this is just a construct to avoid generating composite commands).
- Entity commands are named like DoSomething, they instruct the target entity to do something that might result in different outcomes or fail.
- In the DDD world command message determines unit of work, while specific entity commands map to the methods called upon the target aggregate root.
Essentially command signature could be represented as:
public interface IEntityCommand {}
public sealed class CommandMessage
{
public readonly Guid EntityId;
public readonly IDomainCommand[] Commands;
public readonly long Version;
// constructor
}
where IEntityCommand could be:
public sealed class RenameProject : IEntityCommand
{
public readonly string Name;
// constructor
}
Time tick is merely an event produced by the scheduling infrastructure within the partition. It does not have an identity, but is used to trigger processes, track timeouts and fuel temporal queries (i.e.: buffer, throttle, sample etc).
Event is described by:
- Event is something that happened in the past. It is the history that can't be changed. This intent is expressed in its naming: SomethingChanged.
- Event is associated with the sender's identity and it's version. These two properties together uniquely identify each event and allow subscriber to handle duplicates possibly generated by the scalable infrastructure.
- Event does not have a recipient. It is merely published to the messaging infrastructure. The latter will be responsible for routing the event to it's subscribers (there could be zero or more). It will do so using event's identity and type (first allows routing event to a specific partition, second filters out only the events that the subscriber is interested in).
Failure is the generic unexpected exception that is the result of an attempt to process command. It indicates that something could not happen in the past and is equivalent of Reactive OnNext(Exception) translated to the domain environment. Just like in the case of observations, failure is the last item in the sequence (it terminates the reality).
- Failure includes information about the exception and the command(s) that caused it.
- Since failure includes command information, it logically includes entity identifier and unique message identifier.
- One command could logically fail one or more times (i.e. when message bus tries to handle transient error). This means that in order to uniquely identify a failure (and ensure idempotent operation, where it is needed), each failure should have it's own identity.
- Failure
Published: September 19, 2010.
🤗 Check out my newsletter! It is about building products with ChatGPT and LLMs: latest news, technical insights and my journey. Check out it out