Red Hat blog
This post is about an experience at a customer engagement in which I had the opportunity to use an open source library from the Java Spring Framework with which I was not familiar. The customer has a ReactJS web client using a RESTful service as a controller. The web client needs to invoke services on the back end. However, for security reasons, the web client has no direct access to the back end, so the web client calls a controller REST API, which in turn makes a pass-through call to the back end service REST API.
I was tasked to provide a way for the web client to be notified of ongoing events taking place on the back end whenever a long-running multi-step process was invoked. Since Spring Boot was used for both the web controller and back end, WebFlux was chosen.
WebFlux is a module in the Java Spring 5 Framework. It internally uses Project Reactor and its implementation of the Publisher/Subscriber pattern Flux and Mono. Below is an example of how I implemented one-way push notifications between the web client and the back end service.
What makes this example different from the basic general use examples easily found on the web, is that this example is driven by actual customer requirements constrained by legacy architecture and security needs. The examples are shown and explained in three parts:
- A sequence diagram of the entire solution
- The back end service
- The web client controller
- The web client
Let’s now start with a look at the sequence diagram.
The diagram here shows the flow of the asynchronous subscribe/publish pattern of WebFlux.
- The web client opens and subscribes to the stream residing on the Restful web controller.
- The web client invokes the long running process through the web controller.
- The web controller invokes the long running process while it also subscribes to the additional stream residing on the back end service.
- The long running process publishes messages to the stream as notification events to which the web controller has subscribed.
- Messages received from the web controller published to the first WebFlux stream are received by the web client.
Next let’s look at the Back end web service.
Below is an example of how the WebFlux publisher is set up on the back end using a SseEmitter object to publish events for subscribers to consume.
I did not create a Spring service to be called by the RESTful method as it was not necessary for a WebFlux demonstration. What is important is how this simulated long-running process runs in a worker thread so the WebFlux stream can stay alive, and the SseEmitter object is returned to the caller (line 60). Each event in the process is published to the stream via the send method on line 42. Notice that caught exceptions thrown by the long-running process can be converted to error events and streamed to the caller on line 51. That’s about it. Pretty easy. Now let’s look at the web controller.
When working with the ReactJS web developer, I was told that a separate REST endpoint was needed to open the SseEmitter stream, because the SSE (Server Sent Events) standard does not support the POST method. He needed to use EventSource to open the stream with a GET request. When the stream is open, he uses the fetch method to create the POST request to the actual endpoint that calls the long running process. Below is the endpoint used to create the event stream.
The SseEmitter object is declared as a class member so it can be accessed by the pass-through method for calling the long-running process. Now let’s look at the pass-through method.
This method calls the long-running back end process then subscribes to the WebFlux stream returned by it (line 41 and 42). What is interesting here is that this method is both a subscriber to the back end stream and a publisher for the web client. The first thing to notice on line 35 is produces = MediaType.TEXT_EVENT_STREAM_VALUE that declares the media type of the response. In line 42, the response from the POST request is converted to a Flux object of type Event, which is returned to the web client (line 62). The Flux object then subscribes to the events streamed from the back end service on line 44. Upon receiving an event, the SseEmitter object publishes it for the web app to consume on line 46. Notice the back end service sends a special event to let the controller know when the long-running process has either finished or thrown an exception, so the controller can close the stream (line 48 and 52). Now let’s have a look at the web client.
The example above does not make a POST request, but it does describe how to receive events streaming from the controller. This part of the tutorial is not that important. I just needed a vehicle to demonstrate everything else. There are two things to reiterate here. First, the first EventSource object (Webflux) in the web app is used to open and subscribe to the stream between the web app and the web controller. The reason is due to the fact that EventSource does not support the POST method. Secondly, the second EventSource object (source) is used to call the long-running process via the REST controller. These two webflux streams act in concert to pass messages from the back end through the web controller to the web app. Below is the web client in action via an animated gif that works as well as a video.
And of course, any feedback is appreciated. After all, this document is not just for informational purposes, but to start some collaboration among any and all interested parties.
Webflux is lightweight and easy to use with a broad spectrum of configurations to fit any need, and I hope my experience with it may be of assistance to any application developers out there looking for related solutions.
Connect with Red Hat Services
Learn more about Red Hat Consulting
Learn more about Red Hat Training
Join the Red Hat Learning Community
Learn more about Red Hat Certification
Subscribe to the Training Newsletter
Follow Red Hat Services on Twitter
Follow Red Hat Open Innovation Labs on Twitter
Like Red Hat Services on Facebook
Watch Red Hat Training videos on YouTube
Understand the value of Red Hat Certified Professionals