Developing Reactive Microservices

In this chapter, we will learn how to develop reactive microservices, that is, how to develop non-blocking synchronous REST APIs and asynchronous event-driven services.

We will also learn about how to choose between these two alternatives. Finally, we will see how to create and run manual and automated tests of a reactive microservice landscape.

As already described in Chapter 1 , Introduction to Microservices, the foundation for reactive systems is that they are message-driven---they use asynchronous communication. This enables them to be elastic, in other words, scalable and resilient, meaning that they will be tolerant of failures. Elasticity and resilience together will enable a reactive system to be responsive.

The following topics will be covered in this chapter:

  • Choosing between non-blocking synchronous APIs and event-driven asynchronous services
  • Developing non-blocking synchronous REST APIs
  • Developing event-driven asynchronous services
  • Running manual tests of the reactive microservice landscape
  • Running automated tests of the reactive microservice landscape

Technical requirements

For instructions on how to install tools used in this book and how to access the source code for this book, see:

  • Chapter 21 for macOS
  • Chapter 22 for Windows

The code examples in this chapter all come from the source code in $BOOK_HOME/Chapter07.

If you want to view the changes applied to the source code in this chapter, that is, see what it takes to make the microservices reactive, you can compare it with the source code for Chapter 6 , Adding Persistence . You can use your favorite diff tool and compare the two folders, that is, $BOOK_HOME/Chapter06 and $BOOK_HOME/Chapter07.

Choosing between non-blocking synchronous APIs and event-driven asynchronous services

When developing reactive microservices, it is not always obvious when to use non-blocking synchronous APIs and when to use event-driven asynchronous services. In general, to make a microservice robust and scalable, it is important to make it as autonomous as possible, for example, by minimizing its runtime dependencies. This is also known as loose coupling. Therefore, asynchronous message passing of events is preferable over synchronous APIs. This is because the microservice will only depend on access to the messaging system at runtime, instead of being dependent on synchronous access to a number of other microservices.

There are, however, a number of cases where synchronous APIs could be favorable. For example:

  • For read operations where an end user is waiting for a response
  • Where the client platforms are more suitable for consuming synchronous APIs, for example, mobile apps or SPA web applications
  • Where the clients will connect to the service from other organizations -- where it might be hard to agree on a common messaging system to use across organizations

For the system landscape in this book, we will use the following:

  • The create, read, and delete services exposed by the product composite microservice will be based on non-blocking synchronous APIs. The composite microservice is assumed to have clients on both web and mobile platforms, as well as clients coming from other organizations rather than the ones that operate the system landscape. Therefore, synchronous APIs seem like a natural match.
  • The read services provided by the core microservices will also be developed as non-blocking synchronous APIs since there is an end user waiting for their responses.
  • The create and delete services provided by the core microservices will be developed as event-driven asynchronous services, meaning that they will listen for create and delete events on topics dedicated to each microservice.
  • The synchronous APIs provided by the composite microservices to create and delete aggregated product information will publish create and delete events on these topics. If the publish operation succeeds, it will return with a 202 (Accepted) response, otherwise an error response will be returned. The 202 response differs from a normal 200 (OK) response -- it indicates that the request has been accepted, but not fully processed. Instead, the processing will be completed asynchronously and independently of the 202 response.

This is illustrated by the following diagram:

Figure 7.1: The microservice landscape

First, let's learn how we can develop non-blocking synchronous REST APIs, and thereafter, we will look at how to develop event-driven asynchronous services.