Protocols and Backpressure in Spring WebFlux

Reading Time: 3 minutes

The WebSocket Protocol

Never blocking is one of the main suggestions for dealing with data streams. A client using data from a stream should never block the thread because it does not own it. Putting them in a buffer will stop them from being released. However, buffers have a finite capacity, can overflow, and can lose data. The client should be able to regulate how quickly the stream emits things, which is the only remaining choice. But we need a two-way line of communication for this to happen.

WebSocket is a computer communications protocol, that provides full-duplex communication channels over a single TCP connection. WebSocket is an alternative to HTTP that allows opening a two-way interactive communication between a browser (the client) and a server.

Annotations for enabling WebSocket

@EnableWebSocket: When placed on a Spring configuration class, it enables WebSocket request processing

@EnableSync: A very useful annotation because it enables asynchronous messaging. This means that once the connection opens, the client and server can send messages in parallel.

The RSocket Protocol

Rsocket is a binary application protocol providing Reactive Streams semantics that can be used on top of byte stream transports such as TCP, WebSockets, and Aeron. It was created by engineers at Netflix, the most popular streaming platform nowadays. It enables the asynchronous exchange of messages over a single connection with the following flavors.

  • fire-and-forget (no response): For example, the handler method returns Mono<Void> and declares a parameter of type RequestMessageType; you can view this as a one-to-one communication between clients and servers. HTTP supports this, but the lack of response confuses some browsers.
  • request/response (stream of 1): For example, the handler method returns Mono< ResponseMessageType > and declares a parameter of type RequestMessageType or Mono< RequestMessageType >; you can view this as a one-to-one communication between client and server. HTTP supports this.
  • request/stream (finite stream of many): For example, handler method returns Flux< ResponseMessageType > and declares a parameter of type RequestMessageType or Mono< RequestMessageType >; you can view this as a one-to-many communication between client and server. WebSocket supports this.
  • channel (bidirectional streams): For example, the handler method returns Flux< ResponseMessageType > and declares a parameter of type Flux< RequestMessageType >; you can view this as a many-to-many communication between client and server.

The best thing about RSocket is that there are drivers for Java, JavaScript, Kotlin, .NET, Python, Go, and C++. In theory, this means an application developed in JavaScript can exchange messages with a Java application using this protocol, which means backpressure can be applied at the logical-elements level. 

Here is a sample configuration file that configures the server to start on port 8081 to send and receive messages over WebSocket.

Handling Backpressure

Backpressure is the unicorn of reactive programming. Nearly every software engineer knows how to define it and must deal with it sooner than later. The term backpressure is borrowed from fluid dynamics, but in software, it represents the force opposing the desired flow of data through software.

Backpressure can lead to blockages and data loss, so handling backpressure is writing code to regulate the data flow on the server side and implementing some data-saving mechanism on the client side.

Here is a simple example of handling backpressure using an implementation of Project Reactor’s BaseSubscriber<T>.

@Test
void testBackpressureHandlingOne() {
    var techNews = Flux.fromStream(
            Stream.generate(BookNewReleasesUtil::randomNews))
        .take(20).log(); // server outbound stream
    // client
    techNews.subscribe(new BaseSubscriber<>() {
        int processed;
        final int limit = 5;
@Override
        protected void hookOnSubscribe(Subscription subscription) {
            subscription.request(limit);
        }
        @Override
        protected void hookOnNext(String news) {
            //client logic here
            if (++processed >= limit) {
                processed = 0;
                request(limit);
            }
        }
    });
}

To achieve logical-elements backpressure through the network boundaries, we need an appropriate protocol. That protocol is Rsocket.

Conclusion

To build reactive applications, you need a reactive mindset and to write your code declaratively. Spring WebFlux is an excellent candidate for writing reactive applications that run on a robust JVM platform. Spring WebFlux simplifies threaded work by making it unnecessary to interact with the underlying components parallelizing the work. It provides a lot of operators that simplify transformations of data streams. The resulting code is cleaner, more readable, and more robust.

Server-sent events and the WebSocket protocol are supported. RSocket is a new messaging protocol designed to solve common microservice communication challenges, such as handling backpressure at the logical elements level over TCP. You get modern controls like multiplexing, backpressure, resumption, and routing, and you get multiple messaging modes, including fire-and-forget, request-response, and streaming.

References:

Written by 

Mohd Uzair is a Software intern at Knoldus. He is passionate about java programming. He is recognized as a good team player, a dedicated and responsible professional, and a technology enthusiast. He is a quick learner & curious to learn new technologies. His hobbies include watching movies, surfing youtube, playing video games.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading