Comment on page
A command is an instruction to carry out work. It exercises the domain and results in a change of state. It expects a single handler.
In Brighter, a command processor allows you to use the Command Pattern to separate caller from the executor, typically when separating I/O from domain code. It acts both as a Command Dispatcher which allows the separation of the parameters of a request from the handler that executes that request and a Command Processor that allows you to use a middleware pipeline to provide additional and re-usable behaviors when processing that request.
An event is a fact. The domain may be updated to reflect the fact represented by the event. There may be no subscribers to an event. It may be skinny, a notification, where the fact is the event itself, or fat, a document, where the event provides facts describing a change.
In message oriented middleware, an event stream delivers messages (or records) via a steam. A consumer reads the stream at a specific offset from the start. Consumers can store their offsets to resume reading the stream for where they left off, or reset their offset to re-read a stream. Consumers neither lock, nor delete messages from the stream. For consuming apps to scale, the stream can be partitioned, allowing offsets to be maintained of a partition of the stream. By using separate consumer threads or processes to read a partition, an application can ensure that it is able to reduce the latency of reading the stream.
Examples: Kafka, Kinesis, Redis Streams
The class of applications that deliver a message from one process to another. MoM may send messages either point-to-point (with just a message queue) between sender and receiver, or via a broker, which acts as a dynamic router for messages between sender and receiver. With a broker, the receiver often establishes a subscription to a routing table entry (a routing key or topic) via a message queue or an event stream.
Brighter abstracts a specific type of message-oriented middleware by a Transport.
For simplicity, Brighter only supports transports that have a broker configuration, not point-to-point. If you need point-to-point semantics, configure your routing table entry so that it only delivers to one consuming queue or stream.
A message mapper turns domain code into a message: a header and a body, or turns a message into domain code. Because message oriented middleware typically looks in a header for routing information, it is also where you add routing information via the header.
Each individual transport has code to turn a Brighter format message into a message oriented middleware compatible message, and vice versa, so your code only needs to translate to and from the Brighter format.
In message oriented middleware, a message queue delivers messages via a queue. A consumer locks a message, processes it, and when it acknowledges it, it is deleted from the queue. Other consumers can process the same queue, and read past any locked messages. This allows scaling via the competing consumers pattern. A nack will release the lock and make a message visible in the queue again, sometimes with a delay. A dead-letter-queue (DLQ) can be used with a nack, to limit the number of retries before a message is considered to be "posion pill" and moved to another queue for undeliverable messages.
Examples: SQS, AMQP 0-9-1 (Rabbit MQ), AMQP 1-0 (Azure Service Bus).
Brighter and Darker's pipelines use a "Russian Doll Model" that is, each handler in the pipeline encompasses the call to the next handler, allowing the handler chain to behave like a call stack.
It is analogous to a method on an ASP.NET Controller.
In Darker, a query processor allows you to use the Query Object Pattern to separate caller from the executor, typically when separating the code required to execute a query on a specific database/backing store from the parameters of that query. It acts both as a Query Dispatcher which allows the separation of the parameters of a query from the handler that executes that query and a Query Processor that allows you to use a middleware pipeline to provide additional and re-usable behaviors when processing that query.
A handler is the entry point to domain code. It receives a request, which may be a command or an event. A handler is always part of an internal bus even when the call to the handler was triggered by a service activator receiving a message sent by another process to an external bus. As such a handler forms part of a pipeline.
It is analogous to a method on an ASP.NET Controller.
Request-Reply is a pattern in which there is a request for work and a response.
A common approach is to change state via Brighter and query for the results of that state change via Darker (and return those results to the caller).
If the call to Brighter results in a new entity, and the id for the new entity was not given to the command (for example it relies on the Database generating the id), a common problem is how to then request the details of that newly created entity via Darker. A simple solution is to update the command with the id (as a conceptual out parameter), and then retrieve it from there to use in the Darker query. See update a field on a command for more.
A routing key, also called a topic is the key used by message broker to route published messages to a subscriber.