Using Commands, Events, and Queries in Microservices Communication
Distributed applications require to communicate with each other to accomplish certain business use cases. When designing the inter-component communication, three message constructs requires your attention; Commands, Events, and Queries. Proper classification and using them in the right context can make a significant impact on your application architecture.
This article attempts to discuss each messaging construct’s characteristics, patterns, and potential use cases to apply them.
Messages, producers, consumers, and brokers
A message is a datagram created by producers to distribute information so that consumers can be aware and act accordingly. Producers and consumers communicate directly or through a message broker. Based on the context, the messages exchanged between producers and consumers can be classified as follows.
- Commands
- Events
- Queries
Commands
A Command is a message directed at a receiver to get something done. The producer of a command has an intent and may expect a response from the receiver.
Commands carry the data itself
In enterprise architectures, A command is a way to pass control from the message producer to the consumer. Thus, commands are usually heavy as they carry the full set of instructions to complete an operation. For example, a UI service sends a command to the Order service to process an order. The Command contains every information about the order so that the Order service can complete the processing.
At-least-once delivery and exactly-once processing
A command is a high-value message and must be delivered at least once. A loss of a command message might cause an entire business transaction to fail. For example, we can’t afford to lose a cash deposit transaction.
A command changes the state of a system. Hence, it shouldn’t be processed more than once. Doing so might cause an inconsistent state in the system. For example, we can’t expect an order to be processed more than once. Hence, the consumers of the commands should consider idempotent processing.
Sometimes, commands need to process in an orderly manner
The producer of commands expects the consumer to process them in a particular order. Otherwise, the outcome will be different.
Events
Events are messages that carry the facts about something that happened in the past.
The producer of an event has no expectations that the events will result in any action. Hence, the producer doesn’t expect any response in return.
Publisher/subscriber semantics
Interested consumer(s) can subscribe, listen for events, and take actions depending on their consumption scenario. Events can have multiple subscribers (fanout) or no subscribers at all. Two different subscribers can react to an event with different actions and not be aware of one another.
Generally, event subscriptions are managed by an intermediary like a message broker. When publishers send an event, the broker will route that event to interested subscribers. If a consumer is no longer interested in an event, can unsubscribe. This pattern is known as “publish-subscribe architecture.”
Events are lightweight
Compared to commands, events are lightweight as they carry only a notification about something that happened.
Queries
Queries are a request to look something up. Unlike events or commands, queries are free of side effects; they leave the state of the system unchanged.
Usually, queries are synchronous operations that can be implements over protocols like HTTP or gRPC.
How to choose between Commands and Events
A distributed application is likely to use a combination of commands, events, and queries to implement business use cases. Therefore, it is necessary to analyse and identify all possible inter-component communication use cases to decide upon which messaging to construct to use.
When to use commands
Consider using commands for application use cases that demand:
- End to end message delivery guarantee between message producer and consumer.
- A consumer must process a message exactly once, not more than that.
- A consumer expects to process messages in the order they were published.
- Producer of a command expects a response from the receiver to confirm the completion of a task; as a way of assuring the integrity of a system.
Using a message queue to deliver commands between components will address the above features. As an added advantage, message queues offer competing consumer pattern based message consumption at the receiving end. That allows scaling out the command processors while making sure that each command is processed only by a single consumer.
When to use events
Consider using events if the use cases demand:
- Loose coupling between event producers and consumers where producers are not aware of the recipients of events at all.
- To broadcast state change events to interested services or components in a “fire and forget” style.
- An event will be discarded if there are no subscriptions exist. Doing so shouldn’t impact the business.
Messages brokers that provide pub-sub features are the best way to implement event broadcasting use cases. That way, the subscription handling is taken care of by the broker, allowing you to focus only on building the event publishing or receiving logic.