All of the previous is not to say that one size fits all. When designing a reactive microservice system, you want to choose the best messaging pattern for the purpose. To analyze message needs, it is helpful to categorize the contents as queries, commands, or facts:
Asynchronous messaging provides a simple scalable pattern that you should take advantage of whenever possible. However, synchronous messaging can — and should — be accomplished as efficiently as possible. For example, the sender might wait for a simple acknowledgement from the receiver and continue its work, expecting a reply from the receiver with the answer at some future point. This requires acceptance that it is OK for the system to achieve a consistent state eventually, rather than immediately, as described in Events and Eventual Consistency.
At the system level, Reactive Microservices should be mobile and addressable to keep communication flowing in spite of failures. You should be able to deploy instances of a particular microservice on any available node. When the number of instances and their locations change dynamically, a level of indirection is necessary to shield clients and other services from what is going on behind the scenes. Service discovery mechanisms meet this need by allowing third parties to find and communicate with a microservice without being aware of how many instances are running or where they are running.
With this introduction to events, eventual consistency, and messaging, it’s time to address the elephant in the room, management of state — in particular — persistence. With a variety of microservices handling what used to be contained within one monolith writing to one database, how can you persist state safely without throttling performance or risking unavailability?
In under 15 minutes:
In less than an hour:
Really dig in: