Quick Introduction to Reactive Programming


18 Feb 2019  Sergio Martin Rubio  2 mins read.

Reactive programming is based on asynchronous, non blocking execution, which allows us to make efficient use of a small number of threads.

This paradigm makes use of the Publisher-Subscriber pattern to achieve asynchronous and event-based sequences of data.

Publishers and Operators

Reactor provides two publisher types, both implementing Publisher<T>:

  • Flux<T>: for 0 to N elements
  • Mono<T>: for 0 or 1 element.

On top of those you chain operators — map, flatMap, filter, range… — which work much like the operations offered by the Stream API introduced in Java 8. Each operator returns a new publisher rather than mutating the previous one, and nothing is executed until you subscribe, so the whole chain is only consumed when subscribe() is called.

## Other features

The Reactor API also allows other kind of operations like schedules, publish on a particular thread the subsequent operations (publishOn()) or subscribe all the previous operations on a specific thread (subscribeOn())

Moreover, Reactor 3 is fully integrated with Spring 5, and can be used through the Spring WebFlux framework, so you can create reactive routes. In order to fully make use of the reactive paradigm we will have to use reactive Spring Data and reactor-netty which is built on Netty to provide reactive I/O.

Testing

This library also provides some testing features. StepVerifier allows us to simulate a reactive chain of operations, and finally call verify() as the terminal operation, otherwise, StepVerifier will not subscribe to our sequence and nothing will be asserted.

We can also simulate delays by calling withVirtualTime(). This method takes a supplier as input, and lazily creates an instance of the tested Flux.

Another testing tool is TestPublisher, which allows us to trigger onNext, onComplete or onError events.

## Challenges

  • Debugging: if an error is raised it will only show where the subscription happened, and we will not know where to start debugging. We might need to use debug sessions on our IDE, logs, execute operators on different threads, checkpoints…
  • The complexity of our code might increase.
  • More memory intensive.