Project Reactor essentials

From the beginning, the Reactor library was designed with the aim of omitting callback hell and deeply nested code when building asynchronous pipelines. We described these phenomena and complications caused by them in Chapter 1, Why Reactive Spring? In the quest for linear code, the library's authors formulated an analogy using an assembly line: "You can think of data processed by a reactive application as moving through an assembly line. Reactor is both the conveyor belt and the workstations."

The primary goal of the library is to improve the readability of the code and introduce composability to workflows defined with the Reactor library. The Public API is designed to be high-level but very versatile, but at the same time it does not sacrifice performance. The API provides a rich set of operators (the "workstations" in the assembly analogy), which provide the biggest added value over the "naked" Reactive Streams specification.

The Reactor API encourages operator chaining, which enables us to build complicated, potentially reusable execution graphs. It is important to note that such an execution graph only defines execution flow, but nothing happens until the subscriber actually creates a subscription, so only a subscription triggers actual data flow.

The library is designed for efficient data manipulation, both local and retrieved, as a result of asynchronous requests with potentially faulty IO. This is why error handling operators in Project Reactor are very versatile and, as we are going to see later, encourage writing resilient code.

As we already know, backpressure is an essential property, which the Reactive Streams specification encourages reactive libraries to have, and because Reactor implements the specification, backpressure is a central theme in Reactor itself. So, when talking about Reactive Streams built with Reactor, data travels downstream, from publisher to subscriber. At the same time, subscription and demand control signals are propagated upstream, from a subscriber to a publisher:

Diagram 4.1 Data flow and subscription/demand signal propagation through a reactive stream

The library supports all common modes of backpressure propagation, as follows:

  • push only: When a subscriber asks for an effectively infinite number of elements with subscription.request(Long.MAX_VALUE)
  • pull only: When a subscriber requests the next element only after receiving the previous one: subscription.request(1)
  • pull-push (sometimes called mixed): When a subscriber has real-time control over the demand and the publisher may adapt to the announced speed of data consumption.

Also, when adapting an old API that doesn't support the pull-push model of operation, Reactor offers lots of old-school backpressure mechanisms, namely—buffering, windowing, message dropping, initiating exceptions, and so on. All of these techniques will be covered later in the chapter. In some cases, the aforementioned strategies allow the prefetching of data, even before the actual demand appears, improving the responsiveness of the system. Also, the Reactor API offers enough instruments to smooth out short peaks of user activity and prevent the system from overloading.

Project Reactor is designed to be concurrency agnostic, so it does not enforce any concurrency models. At the same time, it provides a useful set of schedulers to manage execution threads in almost any fashion, and if none of the proposed schedulers fits the requirements, the developer can create their own scheduler with complete low-level control. Thread management in the Reactor library is also covered later in the chapter.

Now, after a brief overview of the Reactor library, let's add it to the project and start investigating its reach API.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.68.28