Messaging shouldn’t be used for queries
When you use messaging to regulate the communication between services it can bring a host of benefits such as improved redundancy, resilience and scalability. It can also promote decoupling by adding an implicit, data-based interface between collaborating services.
However, these benefits are largely dependent on the style of communication as much as the underlying transport. They tend to pre-suppose an asynchronous, one-way style of communication where a process can send commands or events without having to worry about what happens to them. Once the message has been sent it is the responsibility of the queue to deliver it and the recipient to process it.
Queries on the other hand are based on a request\response style of communication where a consumer sends a message and expects a timely response. The communication is inherently synchronous and two-way. If you really do need to respond in real-time then this can undermine many of the benefits of messaging.
Using messaging as a query transport
It’s this need for a fast response which is critical. Messaging does bring increased communication latency and in many query-based scenarios this is not a price worth paying.
For example, message queues typically add redundancy by allowing you to preserve data until it has been fully processed. This is important when you’re trying to provide a processing guarantee, but it adds less value in queries where both the request and response are generally transient and short-lived.
The fault tolerance and resilience that you’d expect to derive from messaging is also compromised in query scenarios. If the server cannot process the request then in most cases a consumer won’t be able to wait around while the problem gets fixed. They will be expected to report failure to the user and let them decide how to proceed.
The de-coupling afforded by messaging does not apply to a query scenario. Given that a request always expects a timely response a query inevitably adds temporal coupling to a system where the consumer depends on a response to complete an operation. This is not mitigated by messaging as it’s the style of communication that creates the coupling rather than the underlying transport.
Where messaging can add value
Messaging can still be invaluable for helping to managing workload in a query scenario. Your service may need to buffer incoming requests to regulate processing, distribute it to processing nodes or manage large spikes in demand.
Although low-latency messaging can help in these scenarios, it would be better situated behind the end-point. This would allow clients to communicate via a simple lightweight protocol, while the service manages demand via messaging. In this sense, the messaging becomes part of the implementation detail of the service rather than the communication transport.
Use a synchronous framework for queries
There is a reason why service bus frameworks such as nServiceBus and MassTransit tend to discourage you from using message-based queries. Services should be autonomous and able to complete processing on their own. If your services need to query each other then it may be a sign that your service boundaries need a re-think.
In most cases where you would want to expose a query interface then the increased complexity and latency that messaging brings is often not worth the effort. Queries are based on a synchronous communication pattern it makes more sense to use a synchronous communication framework such as REST, HTTP or SOAP. These come with an implicit understanding that the exchange will be relatively fast, synchronous and prone to the occasional failure.
That’s really all you need for the majority of query scenarios.