reactive streams in the web (goto berlin)...reactive streams reactive extensions marble diagrams...

36

Upload: others

Post on 25-May-2020

33 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions
Page 2: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Reactive Streams in the Web

Florian Stefan | eBay Classifieds Group | GOTO Berlin 2017

Page 3: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Who am I?▪Florian Stefan ▪mobile.de (eBay Classifieds Group) ▪https://ebaytech.berlin/ ▪ [email protected] | @f_s_t_e_f_a_n ▪https://github.com/florian-stefan/

Page 4: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

HTTP

Why are we here?

Service A

Database

Topic Service B Topic

BFF

Event-Driven Systems

Concurrent Remote Calls

Page 5: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

HTML RenderingServer-Side Rendering

AJAX

BFF

Widget Widget

Widget

Widget Widget

Concurrent Remote Calls

Page 6: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Server-Side Rendering ▪ Time To First Byte ▪ Prerendering / CachingHTML Rendering

Page 7: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

AJAX ▪ Head-of-line blocking ▪ Multiplexing with HTTP/2HTML Rendering

Page 8: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Concurrent Remote Calls

Event-Driven Systems

Distributed Systems

Reactive Streams

Reactive Extensions

Marble Diagrams

RxJava

Reactor

Akka Streams

Backpressure

Declarative Programming

Higher-Order Functions

The Reactive Landscape

Page 9: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Concurrent Remote Calls

Event-Driven Systems

Distributed Systems

Reactive Streams

Reactive Extensions

Marble Diagrams

RxJava

Reactor

Akka Streams

Backpressure

Declarative Programming

Higher-Order Functions

The Reactive Landscape

Page 10: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

public interface Somethings { Something loadById(int id); }

Reactive Extensions

API

Service

some thing

public Something loadById(int id) { return somethings.loadById(id); }

Service API Resource

Network Boundary

Page 11: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Reactive Extensions

API

Service

some thing

public CompletableFuture<Something> loadById(int id) { return supplyAsync(() -> somethings.loadById(id), executor); }

Network Boundary

ResourceService API

Page 12: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

public interface Somethings { void loadById(int id, BiConsumer<Exception, Something> callback); }

public CompletableFuture<Something> loadById(int id) { CompletableFuture<Something> eventualSomething = new CompletableFuture<>(); somethings.loadById(id, (error, something) -> { if (error != null) { eventualSomething.completeExceptionally(error); } else { eventualSomething.complete(something); } }); return eventualSomething; }

Network Boundary

ResourceService API

Reactive Extensions

API

Service

some thing

Page 13: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Reactive ExtensionsCompletableFuture<T>

represents an already scheduled task

completes only once

Flux<T>

represents a building plan (caller has to subscribe)

emits many values

Mono<T>

represents a building plan (caller has to subscribe)

emits at most one value

subscribe { , }✘

Page 14: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Operator

Subscriber

Publisher

Reactive Extensions

map { }

subscribe { }

fromArray { }

[ , , ]

wraps

subscribes to

Page 15: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Reactive Extensions

Circle[] circles = { Circle.of(BLUE), ... }; Flux.fromArray(circles)

.map(circle -> Square.of(circle.getColor()))

.subscribe(...);

.log()

[main] INFO - | onSubscribe() [main] INFO - | ?[main] INFO - | onNext(Square(BLUE))[main] INFO - | onNext(Square(YELLOW))[main] INFO - | onNext(Square(GREEN))[main] INFO - | onComplete()

Page 16: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Concurrent Remote Calls

Event-Driven Systems

Distributed Systems

Reactive Streams

Reactive Extensions

Marble Diagrams

RxJava

Reactor

Akka Streams

Backpressure

Declarative Programming

Higher-Order Functions

The Reactive Landscape

Page 17: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Backpressure

Publisher Subscriber

1

subscribe

onNext( )2345

Page 18: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

5

Backpressure

Publisher Subscriber

onNext( )

ExecutorService executorService = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(capacity) );

ids.stream() .map(id -> executorService .submit(() -> somethings.loadById(id))) .collect(toList()) .stream() .map(waitForSomething()) .forEach(handleSomething());

java.util.concurrent.RejectedExecutionException:Task rejected from ThreadPoolExecutor [ Running, pool size = 2, active threads = 2, queued tasks = 4, completed tasks = 0] ✘

Page 19: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Backpressure

Publisher Subscriber

1

subscribe

onNext( )2345

request(2)request(3)

Page 20: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

5

Backpressure

Publisher Subscriber

onNext( )

ExecutorService executorService = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(capacity) );

Flux.fromIterable(ids)

.log()

.flatMap(id -> Mono.just(id) .map(somethings::loadById) .subscribeOn(scheduler), 3) .doOnNext(handleSomething()) .subscribe();

Scheduler scheduler = Schedulers .fromExecutorService(executorService);

Page 21: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Backpressure

subscribe { }

Calling Thread Scheduler

flatMap { }

subscribeOn { }

.flatMap(id -> Mono.just(id) .map(somethings::loadById) .subscribeOn(scheduler), 3)

Page 22: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

5

Backpressure

Publisher Subscriber

onNext( )

ExecutorService executorService = new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(capacity) );

Scheduler scheduler = Schedulers .fromExecutorService(executorService);

[main] INFO - | onSubscribe() [main] INFO - | ?[main] INFO - | request(3)[main] INFO - | onNext(1)[main] INFO - | onNext(2)[main] INFO - | onNext(3)[pool-1] INFO - | request(1)[pool-1] INFO - | onNext(4)[pool-2] INFO - | request(1)[pool-2] INFO - | onNext(5)[pool-2] INFO - | onComplete()

✓Flux.fromIterable(ids)

.log()

.flatMap(id -> Mono.just(id) .map(somethings::loadById) .subscribeOn(scheduler), 3) .doOnNext(handleSomething()) .subscribe();

Page 23: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Concurrent Remote Calls

Event-Driven Systems

Distributed Systems

Reactive Streams

Reactive Extensions

Marble Diagrams

RxJava

Reactor

Akka Streams

Backpressure

Declarative Programming

Higher-Order Functions

The Reactive Landscape

Page 24: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Progressive HTML RenderingTransfer-Encoding: chunked

BFF

Widget Widget

Widget

Widget Widget

Concurrent Remote Calls

Page 25: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Progressive HTML Rendering

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>

Page 26: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Progressive HTML Rendering

@SpringBootApplication

public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }

}

curl -i -N localhost:8080/hello

@RestController

@GetMapping(value = "hello") public Flux<String> sayHello() { return Flux.interval(Duration.ofMillis(500)).map(tick -> "Hello\n"); }

HTTP/1.1 200 Content-Type: text/plainTransfer-Encoding: chunked

HelloHelloHelloHello

Page 27: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Progressive HTML Rendering

Processor

Subscriber

Publisher Spring 5 WebClient

Reactive-Friendly Thymeleaf View

Reactive Web Server

Page 28: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

URI uri = ...String name = ...

Mono<Pagelet> pageletMono = webClient.get().uri(uri).exchange() .flatMap(res -> res.bodyToMono(String.class)) .map(body -> new Pagelet(name, body));List<Mono<Pagelet>> pageletMonos = ...; ... = Flux.merge(pageletMonos);

Progressive HTML Rendering

Publisher Spring 5 WebClient

Page 29: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

@GetMapping(value = "/widgets") public String widgets(Model model) { List<String> pageletNames = widgetService.getPageletNames(); Flux<Pagelet> pagelets = widgetService.loadPagelets(); model.addAttribute("pageletNames", pageletNames); model.addAttribute("pagelets", new ReactiveDataDriverContextVariable(pagelets, 1)); return "widgets"; }

Progressive HTML Rendering

Processor Reactive-Friendly Thymeleaf View

ReactiveDataDriverContextVariable

Page 30: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

<article th:each="pagelet: ${pagelets}" class="..."> <section class="..."> <div class="..."> <div th:utext="${pagelet.content}" class="..."></div> </div> </section> </article>

Progressive HTML Rendering

Processor Reactive-Friendly Thymeleaf View

List<Mono<Pagelet>> pageletMonos = ...; ... = Flux.merge(pageletMonos);Flux.merge(pageletMonos)

Page 31: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

<script th-inline="javascript" th:each="pagelet : ${pagelets}"> (function() { var element = document.getElementById("[[${pagelet.name}]]"); if(element) { element.innerHTML = "[(${pagelet.content})]"; } })(); </script>

<article th:each="pageletName: ${pageletNames}" class="..."> <section class="..."> <div th:id="${pageletName}" class="..."> <div class="...">...</div> </div> </section> </article>

Progressive HTML Rendering

Processor Reactive-Friendly Thymeleaf View

Page 32: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Progressive HTML Rendering

Page 33: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

What‘s more?▪Reactive Systems ▪Cold Streams vs. Hot Streams ▪Reactive Database Drivers ▪Backpressure Strategies ▪Threaded vs. Evented Server Model ▪WebSockets and Server-Sent Events

Page 34: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Thank you!

Page 35: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions

Questions?

Page 36: Reactive Streams in the Web (GOTO Berlin)...Reactive Streams Reactive Extensions Marble Diagrams RxJava Reactor Akka Streams Backpressure Declarative Programming Higher-Order Functions