DEV Community

Captain Mcwiise
Captain Mcwiise

Posted on

Brief Intro to Reactive Streams with Project Reactor

Source code of the examples on Github

Traditional client/server communication is done by requests, where the server sets a thread to attend every request, and then the client waits for the server to complete a bunch of tasks before getting either a successful or failed response, This is what we know as synchronous and blocking communication.

Regardless the scalability strategy implemented by the server (horizontal or vertical), this sync-blocking communication could be an overhead for the app's performance, so we can use reactive programming to handle threads in a more efficient way.

Let's explore the four communication scenarios using a call center as study case.

Synchronous and Blocking

As we saw above this is the traditional way, where the client will be blocked until getting a response from the server.

sync-blocking

Asynchronous

The client will delegate the communication to the server to another thread, thus the client is released to execute other tasks while the server responses.

async

Non-Blocking

The client does not delegate the communication to a new thread, but registers a callback function where will receive the response after the server processes the request. This scenario also releases the client (main thread) to perform other tasks.

non blocking

Non-Blocking Async

the client delegates the communication to a new thread, so the new thread registers the callback function where will receive the response once the server processes the request. This scenario also releases the client (main thread) to perform other tasks.

non blocking async

Publisher Subscriber Pattern

Reactive programming relies on the Publisher and Subscriber pattern, where the communication between components that emit messages (publishers) and the ones which consume them (subscribers) relies on an external component called broker.

pub sub pattern

Publishers and subscribers are agnostic each other. More about this pattern in further posts about Apache Kafka.

The Reactive Streams API

The reactive streams API provides the specification for non-blocking async streams processing with back pressure mechanism, and Project Reactor is an implementation written in java.

What is Back Pressure?

Having a look at the pub-sub pattern diagram, back pressure is a strategy the reactive streams provide to control the number of messages (items) a subscriber is able to consume from a publisher.

Let's review the 4th interfaces provided by the API, and keep in mind the difference between these 2 concepts:

  • item: this is the element or message sent by a publisher and consumed by a subscriber.
  • signal: a flag emitted by the publisher after an item or a set of items are sent.

Publisher Interface

  • Responsible for emitting items along with a success or failure signals.
  • It also provides a method for the subscribers to register a subscription.

Subscription Interface

  • This is a channel where the subscriber is able to request more items to the publisher (back pressure mechanism).
  • The subscriber can also cancel the subscription using the same channel.

Subscriber Interface

A subscriber reacts to the items and signals emitted by the publisher by the implementation of the following methods:

  • onComplete() The publisher notifies the subscriber that there are no more items to emit, then the publisher is closed.
  • onError(Throwable) The publisher notifies the subscriber that there was an error when emitting the item, then the publisher is closed.
  • onNext() The publisher notifies the subscriber that a next item was just emitted.
  • onSubscribe() This is the initial state, where the publisher notifies the subscriber that the subscription was accepted.

Processor Interface

This is an intermediary stage, a processor can consume an item and emit a new one.

The Project Reactor

As implementation of reactive streams API, reactor is based on two types of publishers: Mono and Flux. Be aware that reactive streams are lazy evaluated, it means that nothing happens until a subscription is created.

Mono

A Mono is a publisher able to emit from zero to 1 items. followed by an onComplete() or onError() signals. Let's explore some basic functions to get started.

Emit And Subscribe

1. public static void emitAndSubscribe(){
2.   var mono = Mono.just("A");
3.   mono.subscribe(
4.     item -> System.out.println(item),
5.     error -> System.out.println(error.getMessage()),
6.     () -> System.out.println("Completed!")
7.   );
8. }
Enter fullscreen mode Exit fullscreen mode
  • line 2: We create mono publisher which emits 1 item.
  • line 3: We create a subscription which receives 3 functions: 2 Consumer and 1 Runnable
  • line 4: the consumer that accepts the item just emitted.
  • line 5: the consumer that accepts an exception in case it is thrown by the publisher.
  • line 6: the runnable which reacts to onComplete() signal.

Outcome:

A
Completed!

Flux

A Flux is a publisher able to emit from zero to many items, followed by an onComplete() or onError() signals. Let's explore some basic functions to get started:

Emit And Subscribe

1. public static void emitAndSubscribe(){
2.   var flux = Flux.fromArray(new String[]{"A", "B", "C"});
3.   flux.subscribe(
4.     item -> System.out.println(item),
5.     error -> System.out.println(error.getMessage()),
6.     () -> System.out.println("Completed!")
7.   );
8. }
Enter fullscreen mode Exit fullscreen mode
  • line 2: We create flux publisher which emits 3 item.
  • line 3: We create a subscription which receives 3 functions: 2 Consumer and 1 Runnable
  • line 4: the consumer that accepts the item just emitted.
  • line 5: the consumer that accepts an exception in case it is thrown by the publisher.
  • line 6: the runnable which reacts to onComplete() signal.

Outcome:

A
B
C
Completed!

Conclusion

The reactor java doc is plenty of methods to work with Monos and Fluxes, we have just covered some basic ones to understand the concepts of publishing and subscribe to get started.

Top comments (0)