Reactive programming is a programming paradigm aimed at maintaining overall coherence by propagating changes from a reactive source (modification of a variable, user input, etc.) to elements dependent on this source.
Reactive applications are more and more important today as they are:
Highly Available: the system must respond quickly no matter what,
Resilient: the system must always remain available, even in case of error or even if it is overloaded,
Message Oriented: the system uses asynchronous messages.
Fullstack Reactive with Spring Webflux and Angular¶
Technically speaking, meeting such requirements implies using a set of frameworks to ensure a smooth user experience.
This stack of reactive-compliant web frameworks goes from the backend with Spring WebFlux to the frontend with Angular.
Built on the Reactive Streams API (a standard for asynchronous stream processing with non-blocking back pressure), Spring WebFlux allows to run non-blocking servers such as Netty.
It uses the reactive library Reactor which provides the Mono and Flux API types to work on single data (Mono) and sequences (Flux).
Angular extensively uses the RxJs library for user events propagation through UI components and services, but also for connections with the backend:
The HTTP service returns Observables.
This allows us to use the same mix of asynchronous and functional programming in both our Java server code and in our TypeScript UI code, the APIs for Reactor and RxJS being quite similar.
More importantly, with a fully reactive stack, changes can be propagated seamlessly everywhere in our application.
When a user interacts with the UI, an HTTP request is sent to the server and the change is made on the backend.
But how to propagate independent changes occurring on the server to the UI? By using Server Sent Events.
Web browser have a maximum number of connections per hostname (usually 6, for the whole browser), and since SSE keeps an open connection to the server, you should not open too many SSE streams at the same time,
Let's start by seeing how to handle Server-Sent-Events in Spring WebFlux to dispatch StorageWatcherEvents.
A StorageWatcherEvent is a simple bean that contains a StorageNode (the representation of a File in a tree) and an event: created, modified or deleted.
Directory watching is made using the directory-watcher project and exposed by a Spring service called StorageWatcherService.
Spring will automatically handle all requests with the Accept header to text/event-stream as an SSE request an answer accordingly:
Note: You can force it with the produces annotation configuration : @GetMapping(path = "/watch", produces = MediaType.TEXT_EVENT_STREAM_VALUE).
There is issue with this solution through: if no event is generated by the watcher.watch() for a while, the connection may be closed if it goes through an HTTP proxy.
It allows us to create ServerSentEvent with only a comment ServerSentEvent.<T>builder().comment("keep alive").build() and inject them in the Flux periodically.
Then we can simply use this service in our REST controller and return directly the Flux<ServerSentEvent<StorageWatcherEvent>>;
The /files/watch endpoint now returns a :keep-alive comment every 15 second, along with the normal events that contain the JSON of a StorageWatcherEvent object:
To call this endpoint from Angular you need an EventSource, let's have a look at it!