Note
|
This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website. |
Learn how to integrate RESTful Java microservices with a reactive system by using MicroProfile Reactive Messaging.
You will learn how to integrate RESTful Java microservices with a reactive system by using MicroProfile Reactive Messaging. RESTful Java microservices don’t use reactive concepts, so you will learn how to bridge the gap between the two using the RxJava library. In this guide, you will modify two microservices in an application so that when a user hits the RESTful endpoint, the microservice generates producer events.
The application in this guide consists of two microservices, system
and inventory
. The following diagram illustrates the application:
Every 15 seconds, the system
microservice calculates and publishes events that contain its current average system load. The inventory
microservice subscribes to that information so that it can keep an updated list of all the systems and their current system loads. The current inventory of systems can be accessed via the /systems
REST endpoint.
You will update the inventory
microservice to subscribe to a PUT
request response. This PUT
request response accepts a specific system property in the request body, queries that system property on the system
microservice, and provides the response. You will also update the system
microservice to handle receiving and sending events that are produced by the new endpoint. You will configure new channels to handle the events that are sent and received by the new endpoint. To learn more about how the reactive Java services that are used in this guide work, check out the Creating reactive Java microservices guide.
You need to have Docker installed. For installation instructions, refer to the official Docker documentation. You will build and run the microservices in Docker containers. An installation of Apache Kafka is provided in another Docker container.
Triggering.
Navigate to the start
directory to begin.
The inventory
microservice records and stores the average system load information from all of the connected system microservices. However, the inventory
microservice does not contain an accessible REST endpoint to control the sending or receiving of reactive messages. Add the /data
RESTful endpoint to the inventory
service by replacing the InventoryResource
class with an updated version of the class.
Replace theInventoryResource
class.inventory/src/main/java/io/openliberty/guides/inventory/InventoryResource.java
InventoryResource.java
link:finish/inventory/src/main/java/io/openliberty/guides/inventory/InventoryResource.java[role=include]
The updateSystemProperty()
method creates the /data
endpoint that accepts PUT
requests with a system property name in the request body. The propertyNameEmitter
variable is an RxJava Emitter
interface that sends the property name request to the event stream, which is Apache Kafka in this case.
The sendPropertyName()
method contains the Flowable.create()
RxJava method, which associates the emitter to a publisher that is responsible for publishing events to the event stream. The publisher in this example is then connected to the @Outgoing("requestSystemProperty")
channel, which you will configure later in the guide. MicroProfile Reactive Messaging takes care of assigning the publisher to the channel.
The Flowable.create()
method also allows the configuration of a BackpressureStrategy
object, which controls what the publisher does if the emitted events can’t be consumed by the subscriber. In this example, the publisher used the BackpressureStrategy.BUFFER
strategy. With this strategy, the publisher can buffer events until the subscriber can consume them.
When the inventory
service receives a request, it adds the system property name from the request body to the propertyNameEmitter
FlowableEmitter
interface. The property name sent to the emitter is then sent to the publisher. The publisher sends the event to the event channel by using the configured BackpressureStrategy
object when necessary.
The system
microservice is the producer of the messages that are published to the Kafka messaging system as a stream of events. Every 15 seconds, the system
microservice publishes events that contain its calculation of the average system load, which is its CPU usage, for the last minute. Replace the SystemService
class to add message processing of the system property request from the inventory
microservice and publish it to the Kafka messaging system.
Replace theSystemService
class.system/src/main/java/io/openliberty/guides/system/SystemService.java
SystemService.java
link:finish/system/src/main/java/io/openliberty/guides/system/SystemService.java[role=include]
A new method that is named sendProperty()
receives a system property name from the inventory
microservice over the @Incoming("propertyRequest")
channel. The method calculates the requested property in real time and publishes it back to Kafka over the @Outgoing("propertyResponse")
channel. In this scenario, the sendProperty()
method acts as a processor. Next, you’ll configure the channels that you need.
The system
and inventory
microservices each have a MicroProfile Config property file in which the properties of their incoming and outgoing channels are defined. These properties include the names of channels, the topics in the Kafka messaging system, and the associated message serializers and deserializers. To complete the message loop created in the previous sections, four channels must be added and configured.
Replace the inventory/microprofile-config.properties file.
inventory/src/main/resources/META-INF/microprofile-config.properties
inventory/microprofile-config.properties
link:finish/inventory/src/main/resources/META-INF/microprofile-config.properties[role=include]
The newly created RESTful endpoint requires two new channels that move the requested messages between the system
and inventory
microservices. The inventory
microservice microprofile-config.properties
file now has two new channels, requestSystemProperty
and addSystemProperty
. The requestSystemProperty
channel handles sending the system property request, and the addSystemProperty
channel handles receiving the system property response.
Replace the system/microprofile-config.properties file.
system/src/main/resources/META-INF/microprofile-config.properties
system/microprofile-config.properties
link:finish/system/src/main/resources/META-INF/microprofile-config.properties[role=include]
Replace the system
microservice microprofile-config.properties
file to add the two new propertyRequest
and propertyResponse
channels. The propertyRequest
channel handles receiving the property request, and the propertyResponse
channel handles sending the property response.
Build the system
and inventory
microservices using Maven and then run them in Docker containers.
Start your Docker environment. Dockerfiles are provided for you to use.
To build the application, run the Maven install
and package
goals from the command line in the start
directory:
mvn -pl models install
mvn package
Run the following commands to containerize the microservices:
docker build -t system:1.0-SNAPSHOT system/.
docker build -t inventory:1.0-SNAPSHOT inventory/.
Next, use the provided script to start the application in Docker containers. The script creates a network for the containers to communicate with each other. It also creates containers for Kafka, Zookeeper, and the microservices in the project. For simplicity, the script starts one instance of the system
service.
.\scripts\startContainers.bat
./scripts/startContainers.sh
The application might take some time to become available. After the application is up and running, you can access it by making a GET request to the /systems
endpoint of the inventory
service.
Visit the http://localhost:9085/health URL to confirm that the inventory
microservice is up and running.
When both the liveness and readiness health checks are up, go the http://localhost:9085/inventory/systems URL to access the inventory
microservice. You see the CPU systemLoad
property for all the systems:
{
"hostname":"30bec2b63a96",
"systemLoad":1.44
}
You can revisit the http://localhost:9085/inventory/systems URL after a while and the value of the systemLoad
property for the systems is changed.
Make a PUT
request on the http://localhost:9085/inventory/data
URL to add the value of a particular system property to the set of existing properties. For example, run the following curl
command:
If curl
is unavailable on your computer, use another client such as Postman, which allows requests to be made with a graphical interface.
curl -X PUT -d "os.name" http://localhost:9085/inventory/data --header "Content-Type:text/plain"
In this example, the PUT
request with the os.name
system property in the request body on the http://localhost:9085/inventory/data
URL adds the os.name
system property for your system.
You see the following output:
Request successful for the os.name property
The system
service is available so the request to the service is successful and returns a 200
response code.
You can revisit the http://localhost:9085/inventory/systems URL and see the os.name
system property value is now included with the previous values:
{
"hostname":"30bec2b63a96",
"os.name":"Linux",
"systemLoad":1.44
}
Run the following script to stop the application:
.\scripts\stopContainers.bat
./scripts/stopContainers.sh
system/microprofile-config.properties
link:finish/system/src/main/resources/META-INF/microprofile-config.properties[role=include]
This application has only one instance of the system
service. The inventory
service collects system properties of all system
services in the application. As an exercise, start multiple system
services to see how the application handles it. When you start the system
instances, you must provide a unique group.id
through the MP_MESSAGING_INCOMING_PROPERTYREQUEST_GROUP_ID
environment variable.
You successfully integrated a RESTful microservice with a reactive system by using MicroProfile Reactive Messaging.