Reactive API with Spring WebFlux

(22-10-24 ~ 22-11-03) Learning Reactive Spring from YouTube course - Build Reactive RESTful APIs using Spring Boot/WebFlux.

1. Why Reactive Programming - Part. 1

Traditional Method

Spring MVC

Handling concurrent requests

  • Managed by server.tomcat.max-threads

  • default = 200

  • can be overridden in application.yml

  • Each thread takes some memory

  • Common stack size is 1MB.

  • Higher the thread pool size, higher the memory consumption!

  • Applications really perform poor with less memory available.

  • Load is handled

    • Most popular approach: horizontal scaling.

  • Kubernetes or some container orchestration.

  • We have limitation on handling many concurrent users.

  • With WebFlux, …

    • We’re moving away from “Thread Per Request Model”.

    • We can handle a higher load of requests with less number of threads.

2. Why Reactive Programming - Part. 2

Traditional REST API Design

  • repository.findById (DB call, blocking) (1ms)

  • restTemplate (rest call synchronous, blocking) (1ms)

(= 2ms)

We call this traditional way imperative style APIs

  • top-down approach

  • blocking and synchronous

  • inefficient use of resource

We need to make calls async, non-blocking

Currently we have in Java:

  • Callbacks

  • Futures

Callbacks

  • Complex

  • No return value.

  • Code is hard to read and maintain.

  • Leads to callback hell.

Future

  • Another alternative to write async in Java.

  • Returns Future instance.

  • Hard to compose multiple async operations.

Completable Future

  • Introduced as part of Java 8

  • Supports functional style API

  • Easy to compose multiple async operations.

  • Not a great fit async call with multiple items.

Traditional REST API Design (Again)

repository.getAllItems()

  • Application might crash with Out Of Memory error.

  • Client might be overwhelmed with huge data.

  • How to avoid this from happening?

    • BackPressure - “You’re sending too much data. Please slow down”

    • We’ll get to it.

    • Not compatible in traditional REST API design.

Better API Design

  • Asynchronous and Non-blocking.

  • Move away from Thread Per Request model.

  • Use fewer threads.

  • Back Pressure compatible.

3. What is Reactive Programming?

  • New programming paradigm.

  • Async and non-blocking.

  • Data flow as an Event/Message-Driven stream.

  • Functional Style Code (Just like Stream API introduced in Java 8).

  • Back Pressure on Data Streams.

Imperative Programming

List<Item> items = itemRepository.getAllItems();
  1. Invoke DB for Data from App to Databasee

  2. Blocked and Waiting…

  3. Data returned from from Database to App

  • Synchronous and blocking communication Model.

Reactive Programming

  • Data flow as an event driven stream.

    • Message and event refer to the same thing.

  • One Event or Message for every result item from Data Source.

  • Data Sources:

    • Database

    • External Service

    • File etc.

  • One Event or Message for completion or error.

Reactive Programming - onComplete

List<Item> items = itemRepository.getAllItems();

  • Data will be pushed to application as a stream (for every single item) until all items are pushed to the application.

  • onNext(item) - Data stream events.

  • Once all the items are pushed, onComplete is called.

Reactive Programming - onError

Reactive Programming - No Data

Reactive Programming - No Data

itemReactiveRepository.save(item);
  • Successful - onComplete

  • Unsuccessful - onError

Functional Style Code

  • Similar to Streams API.

  • Easy to work with lambdas.

@PutMapping("/{id}")
public Mono<ResponseEntity<Item>> updateOffer(
        @PathVariable(value = "id") String id,
        @RequestBody Item item) {
    return itemRepository.findById(id) // Mono<Item>
            .flatMap(currentItem -> {
                currentItem.setPrice(item.getPrice());
                return itemRepository.save(currentItem);
            }) // Mono<Item>
            .log() // Mono<Item>
            .map(updateItem -> new Responsibility<>(updateItem, HttpStatus.OK)) // Mono<ResponseEntity<Item>>
            .log() // Mono<ResponseEntity<Item>>
            .defaultIfEmpty(new Response<>(HttpStatus.NOT_FOUND));
}

Back Pressure on Data Stream

  • Use back pressure to tell data source to slow down.

  • Handy when building stable systems using reactive programming.

4. Reactive Streams Specification

What is Reactive Stream Specification?

  • Specification or Rules for a Reactive Stream.

  • Who created?

    • Engineers from:

      • Pivotal

      • Netflix

      • LightBend

      • Twitter

      • etc.

Reactive Stream Specification

  • Publisher

  • Subscriber

  • Subscription

  • Processor

Publisher

public interface Publisher<T> {
    public void subscribe(Subscribe<? super T> s);
}
  • Accepts the subscriber instance to subscribe registers to the publisher.

  • Represents the Data Source

    • Database

    • External Service etc.

Subscriber

public interface Subscriber<T> {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}
  • onNext - Nothing but a data stream.

  • onComplete - Signal for normal data.

  • onError - Signal for when error happened.

  • onSubscribe - Has Subscription object as input.

Subscription

public interace Subscription {
    public void request(long n);
    public void cancel();
}

Publisher/Subscriber Event Flow - Overview

  • Publisher - Data producer or Data emitter.

  • Subscriber - Read the data from publisher. Synonymous to Consumer.

  • 5 types of events. Numbers in order.

  • Number n to specify how many you need to receive from publisher.

Publisher/Subscriber Event Flow - Cancel

  • Subscribe has option to call cancel method.

  • cancel - We are cancelling the subscription and the publisher will not be publishing any event to the subscriber.

Processor

public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
  • Nothing but a combination of Subscriber and Publisher.

5. Reactive Libraries

What is a Reactive Library?

  • Implementation of Reactive Streams Specification.

    • Publisher

    • Subscriber

    • Subscription

    • Processor

Reactive Libraries

  • RxJava

  • Reactor

  • Flow Class - JDK 9

Reactor or Project Reactor

  • Built and maintained by Pivotal.

  • Recommended Library to work with Spring Boot. (Default)

Reference Guides

6. Introduction to Project Reactor

We’ll focus on:

  • reactor-core

  • reactor-test

  • reactor-netty

7. Reactor Types - Flux and Mono

reactor-core

  • Core library for Project Reactor.

  • Implementation of Reactive Streams Specification.

  • Java 8 (Minimum)

  • Flux and Mono

  • Reactive Types of project reactor.

  • Flux - Represents 0 to N elements.

  • Mono - Represents 0 to 1 element.

Flux - 0 to N elements

Explained using the marble diagrams.

  • Marbles at the top represent the actual data.

  • The operator in the middle represents filtering, transformation and a lot of other operations to transform one data to another form.

  • Marbles at the bottom represent the final output which will be sent to the subscriber.

  • Vertical lines mean uncomplete. (Meaning no more data to send.)

Flux
    .just("Spring", "Spring Boot", "Reactive Spring Boot")
    .map(s -> s.concat("flux"))
    .subscribe(System.out::println);

Mono - 0 to 1 element

  • e.g., request one element from DB, REST, …

Mono
    .just("Spring")
    .map(s -> s.concat("flux"))
    .subscribe(System.out::println);

11. Introduction to Spring Boot 2

https://spring.io/reactive

  • A complete shift with reactive stack.

  • Reactor can be used in both reactive and servlet stack — that’s why it’s on the top!

17. Introduction to Functional Web in Spring WebFlux

Spring WebFlux - Functional Web

  • Use Functions to route the request and response.

  • The functional web consists of two parts: RouterFunction and HandlerFunction.

  • A client makes a request to the server.

  • The request will be forwarded to the RouterFunction first. (Routing)

  • And if it has an appropriate mapping, then the request will be forwarded to the HandlerFunction, which will do the complete process of reading, processing, assigning the response back to the server. (Handling)

RouterFunction

  • Used to route the incoming request.

  • Similar to the functionality of @RequestMapping annotation.

HandlerFunction

  • Handles the request and response.

  • Similar to the function body of @RequestMapping annotation.

  • Has two new classes - ServerRequest and ServerResponse.

    • ServerRequest represents the HttpRequest.

    • ServerResponse represents the HttpResponse.

Source Codes

https://github.com/litsynp/learn-reactive-spring

Credits

Why Reactive Programming - Part 1 ? - Build Reactive API Using Spring Boot/Spring WebFlux

Last updated