Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJava, RxJava 2, Reactor: State of the art of Reactive Streams on the JVM

RxJava, RxJava 2, Reactor: State of the art of Reactive Streams on the JVM

RxJava is used on Android or in backend side thanks to Hystrix. RxJava 2 is now available and will be able to use the path build by the previous version. Pivotal promote Reactor that will be available in Spring Boot 2.

What is the differences between each of these implementations of the Reactive Streams? Why chose RxJava 2 over Reactor or over RxJava?

This conference talk will focus on the history of each implementation then will compare APIs, performances and use cases of these Reactive Streams.

- DevDays Vilinus - may 2018

David

May 23, 2018
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. Got a question
    during this session? 

    Post it on sli.do
    ( #K100 )

    View Slide

  2. RxJava, RxJava 2, Reactor
    State of the art of Reactive Streams on the JVM

    View Slide

  3. David
    Wursteisen

    View Slide

  4. View Slide

  5. Writing asynchronous code: 

    it sucks

    View Slide

  6. Future
    ExecutorService ex = Executors.newCachedThreadPool();

    Future future = ex.submit(() -> longProcessing());

    String result = future.get();
    Blocking call

    View Slide

  7. Future
    Future> future1 = /* ... */

    Future> future2 = /* ... */

    Future> future3 = /* ... */

    Future> future4 = /* ... */

    Future> future5 = /* ... */
    Optimal
    Orchestration ?

    View Slide

  8. Callback
    RemoteService service = buildRemoteService();

    service.getUser(id -> {

    service.getData(id, data -> {

    service.getSomething(data, whut -> {
    service.neverEndingCallBack(whut, () -> {
    });
    });

    });

    });
    Callback Hell

    View Slide

  9. Relationship Status:

    it’s complicated

    View Slide

  10. The problem
    of synchronous code

    View Slide

  11. Synchronous
    Waiting for the
    response
    Caller
    Called

    View Slide

  12. Impact on
    response time
    Slow server

    View Slide

  13. It never works!
    It piss me off!

    View Slide

  14. Asynchronous
    Caller
    Called
    Continuous work

    View Slide

  15. Asynchronous allow to take advantage of
    the waiting time

    View Slide

  16. Minimal impact
    on the response
    time

    View Slide

  17. Write asynchronous code
    easily?

    View Slide

  18. Emergence 

    of different approaches

    View Slide

  19. 2
    Reactive Streams

    View Slide

  20. Reactive Streams
    Reactive Streams API
    RxJava 2 Reactor
    Interface
    Implementation

    View Slide

  21. Reactive Streams API is 

    a bridge 

    between implementations

    View Slide

  22. Reactive Streams contract
    onSubscribe onNext onError
    onComplete

    View Slide

  23. RxJava is
    not compatible 

    with Reactive Streams
    (You’ll have to use an adapter: RxJavaReactiveStreams)
    https://github.com/ReactiveX/RxJavaReactiveStreams

    View Slide

  24. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams

    View Slide

  25. onNext * ( onError | onComplete )

    onNext * ( onError | onCompleted )
    RxJava
    Reactive Streams
    Different name

    View Slide

  26. Common
    approach

    View Slide

  27. A P I t o h a n d l e e v e n t s
    synchronously or asynchronously
    through a flow of events

    View Slide

  28. View Slide

  29. Map ( ⃝ →
    ⬛)

    View Slide

  30. View Slide

  31. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);

    View Slide

  32. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Push of the result

    View Slide

  33. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Get Luke’s vehicles
    Get Luke’s starships

    View Slide

  34. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Merge of two flows

    View Slide

  35. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Really execute the code

    View Slide

  36. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Flow of events

    View Slide

  37. remoteApi.people(1).flatMap(luke -> {

    Observable vehicles = Observable.from(luke.getVehiclesIds())

    .flatMap(remoteApi::vehicle)

    .map(vehicle -> luke.getName() + " can drive " + vehicle.getName());


    Observable starships = Observable.from(luke.getStarshipsIds())

    .flatMap(remoteApi::starship)

    .map(starship -> luke.getName() + " can fly with " + starship.getName());


    return Observable.merge(vehicles, starships);

    }).subscribe(System.out::println);
    Flow of events
    Flow of events

    View Slide

  38. View Slide

  39. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io()) 

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();

    View Slide

  40. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Listen for clicks

    View Slide

  41. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Execution context
    switch

    View Slide

  42. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Asynchronous call to
    a web service

    View Slide

  43. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Execution context
    switch

    View Slide

  44. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Update on the UI

    View Slide

  45. Button btn = new Button();

    btn.setText("Click Me");


    JavaFx.fromClick(btn) // Observable

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData()) // Observable

    .observeOn(javaFx()) 

    .doOnNext(value -> btn.setText("Data: " + value))

    .subscribe();
    Flow of events

    View Slide

  46. Thanks to RxJava
    and Reactor

    View Slide

  47. Writing asynchronous code: 

    it sucks

    View Slide

  48. Once upon a time…

    View Slide

  49. Creation of 

    Reactive Extensions
    Creation of RxJava
    Active Participation
    Resumption of 

    RxJava & RxJava 2
    Creation of Reactor
    Work on Reactor

    View Slide

  50. RxJava 

    is a 

    proved

    technologie

    View Slide

  51. Reactor

    benefits from the experience of

    RxJava
    (and vice versa)

    View Slide

  52. Object types

    View Slide

  53. Observable

    View Slide

  54. View Slide

  55. View Slide

  56. View Slide

  57. View Slide

  58. View Slide

  59. Single

    View Slide

  60. View Slide

  61. Completable

    View Slide

  62. View Slide

  63. RxJava
    Contrat Backpressure
    Observable [N] Yes
    Single [1] No
    Completable [0] No
    Added afterward
    Web service
    call
    Background
    process

    View Slide

  64. Listen a websocket, for each
    received command, compose a
    response by calling 3 different
    webservices, then execute 2 jobs
    sequentially ?

    View Slide

  65. Listen a websocket, for each
    received command, compose a
    response by calling 3 different
    webservices, then execute 2 jobs
    sequentially ?

    View Slide

  66. Listen a websocket, for each
    received command, compose a
    response by calling 3 different
    webservices, then execute 2 jobs
    sequentially ?

    View Slide

  67. Listen a websocket, for each
    received command, compose a
    response by calling 3 different
    webservices, then execute 2 jobs
    sequentially ?

    View Slide

  68. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));

    View Slide

  69. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Listen a websocket
    Observable

    View Slide

  70. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Webservices composition
    Single

    View Slide

  71. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Completable
    2 jobs executions

    View Slide

  72. websocket("/topics/cmd")

    .observeOn(Schedulers.io())

    .switchMap(cmd ->

    Single.zip(

    api.getActions(),

    api.getScore(),

    api.getUserData(),

    this::composeResult).toObservable())

    .observeOn(Schedulers.computation())

    .concatMap(result -> updateDb(result).andThen(getLastResults()))

    .subscribe(last -> System.out.println("last results -> " + last));
    Listen a websocket
    Observable Webservices composition
    Single
    Completable
    2 jobs executions

    View Slide

  73. RxJava 2
    Contrat Backpressure
    Observable [N] No
    Single [1] No
    Completable [0] No
    Maybe [0|1] No New!
    Close to Java 8
    Optional

    View Slide

  74. Maybe

    View Slide

  75. View Slide

  76. Backpressure
    using RxJava 2

    View Slide

  77. Consumer

    View Slide

  78. Consumer
    To many things !

    View Slide

  79. backpressure

    View Slide

  80. MissingBackpressureException ?

    View Slide

  81. acceptedIntent

    .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))

    .concatMap(intent -> approximatedEngine.detectCurrentPlace())

    .doOnNext(score -> Log.info(TAG, "Scan completed with result " + score))

    .concatMap(this::detectSleepMode)

    .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))

    .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))

    .subscribe()

    View Slide

  82. acceptedIntent

    .filter(intent -> !intent.getBooleanExtra("UpdatePhoneMode", false))
    .onBackpressureDrop()

    .concatMap(intent -> approximatedEngine.detectCurrentPlace())

    .doOnNext(score -> Log.info(TAG, "Scan completed with result " + score))

    .onBackpressureDrop()
    .concatMap(this::detectSleepMode)

    .onBackpressureDrop()

    .concatMap((score) -> isNewPlace(score.getScore().getPlace()).map(p -> score))

    .doOnNext((p) -> Log.info(TAG, "Current place found is : " + p))

    .subscribe()
    Added while I
    panicked

    View Slide

  83. RxJava 2
    Contrat Backpressure
    Observable [N] No
    Single [1] No
    Completable [0] No
    Maybe [0|1] No New!
    Close to Java 8
    Optional

    View Slide

  84. RxJava 2
    Contrat Backpressure
    Observable [N] No
    Single [1] No
    Completable [0] No
    Maybe [0|1] No
    Flowable [N] Yes
    New!
    Observable with 

    back pressure
    Close to Java 8
    Optional

    View Slide

  85. Observable
    → less than 1000 events
    → User interface management
    → To be used instead of Java 8 Streams
    Flowable
    → more than 10 000 events
    → Control the data flow
    → Network stream with flow management

    View Slide

  86. What does Reactor offer ?

    View Slide

  87. Flux
    Mono
    Maximum of 1
    element

    View Slide

  88. Reactor
    Contrat Backpressure
    Flux [N] Yes
    Mono [0|1] Yes
    Identical to
    Flowable
    Flux with only 

    1 element

    View Slide

  89. Object types and

    Reactive Streams

    View Slide

  90. Publisher
    Flux Flowable
    Reactive Streams

    View Slide

  91. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();

    View Slide

  92. Flux.range(1, 10)

    .flatMap(i -> Flux.just(1))

    .subscribe();
    Publisher

    View Slide

  93. Flux.range(1, 10)

    .flatMap(i -> Flowable.just(1))

    .subscribe();
    Publisher
    RxJava 2

    View Slide

  94. Flowable.defer(() -> Flux.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2 Reactor

    View Slide

  95. Flux.defer(() -> Flowable.range(1, 10))

    .subscribe(System.out::println);
    RxJava 2
    Reactor

    View Slide

  96. You can use a library
    which use RxJava 2 in
    your Reactor project
    (and vice versa)

    View Slide

  97. Operators

    View Slide

  98. Consequent and homogenous
    Catalogue

    View Slide

  99. all amb ambArray ambWith any as awaitOnSubscribe blockFirst blockFirstMillis blockLast blockLastMillis
    blockingFirst blockingForEach blockingIterable blockingLast blockingLatest blockingMostRecent blockingNext
    blockingSingle blockingSubscribe buffer bufferMillis bufferSize bufferTimeout bufferTimeoutMillis bufferUntil
    bufferWhile cache cacheWithInitialCapacity cancelOn cast checkpoint collect collectInto collectList collectMap
    collectMultimap collectSortedList combineLatest combineLatestDelayError compose concat concatArray
    concatArrayDelayError concatArrayEager concatDelayError concatEager concatMap concatMapDelayError
    concatMapEager concatMapEagerDelayError concatMapIterable concatWith contains count create debounce
    defaultIfEmpty defer delay delayElements delayElementsMillis delayMillis delaySubscription delaySubscriptionMillis
    dematerialize distinct distinctUntilChanged doAfterNext doAfterTerminate doFinally doOnCancel doOnComplete
    doOnEach doOnError doOnLifecycle doOnNext doOnRequest doOnSubscribe doOnTerminate elapsed elementAt
    elementAtOrError empty equals error filter first firstElement firstEmitting firstEmittingWith firstOrError flatMap
    flatMapCompletable flatMapIterable flatMapMaybe flatMapSequential flatMapSingle forEach forEachWhile from
    fromArray fromCallable fromFuture fromIterable fromPublisher fromStream generate getClass getPrefetch groupBy
    groupJoin handle hasElement hasElements hashCode hide ignoreElements interval intervalMillis intervalRange
    isEmpty join just last lastElement lastOrError lift limitRate log map mapError materialize merge mergeArray
    mergeArrayDelayError mergeDelayError mergeSequential mergeWith never next notify notifyAll observeOn ofType
    onBackpressureBuffer onBackpressureDrop onBackpressureError onBackpressureLatest onErrorResumeNext
    onErrorResumeWith onErrorReturn onErrorReturnItem onExceptionResumeNext onTerminateDetach parallel publish
    publishNext publishOn range rangeLong rebatchRequests reduce reduceWith repeat repeatUntil repeatWhen
    replay replayMillis retry retryUntil retryWhen safeSubscribe sample sampleFirst sampleFirstMillis sampleMillis
    sampleTimeout scan scanWith sequenceEqual serialize share single singleElement singleOrEmpty singleOrError
    skip skipLast skipMillis skipUntil skipUntilOther skipWhile sort sorted startWith startWithArray strict subscribe
    subscribeOn subscribeWith switchIfEmpty switchMap switchMapDelayError switchOnError switchOnNext
    switchOnNextDelayError take takeLast takeMillis takeUntil takeUntilOther takeWhile test then thenEmpty thenMany
    throttleFirst throttleLast throttleWithTimeout timeInterval timeout timeoutMillis timer timestamp to toFuture toIterable
    toList toMap toMultimap toObservable toSortedList toStream toString transform unsafeCreate unsubscribeOn using
    wait window windowMillis windowTimeout windowTimeoutMillis windowUntil windowWhile withLatestFrom zip
    zipArray zipIterable zipWith zipWithIterable

    View Slide

  100. RxJava RxJava 2 Reactor
    flatMap flatMap flatMap
    Emit Noe, one or
    more events
    amb amb firstEmitting
    Emit events from the
    first emitting stream
    … … … …
    debounce debounce N/A
    Ignore events during
    a time laps

    View Slide

  101. RxJava RxJava 2 Reactor
    flatMap flatMap flatMap
    Emit Noe, one or
    more events
    amb amb firstEmitting
    Emit events from the
    first emitting stream
    … … … …
    debounce debounce N/A
    Ignore events during
    a time laps
    Renamed

    View Slide

  102. Operators
    cover
    a lot of scenarios

    View Slide

  103. Nota bene

    View Slide

  104. https://github.com/ReactiveX/RxJava/wiki/Implementing-custom-operators-(draft)
    writing operators is hard
    when one writes an operator, the Observable
    protocol, unsubscription, backpressure and
    concurrency have to be taken into account and
    adhered to the letter

    View Slide

  105. Writing a new operator with RxJava 2
    is more complex
    than with RxJava

    View Slide

  106. Make a application
    Reactive

    View Slide

  107. Reactive
    Reactive
    Synchronous API
    Callback
    Reactive
    Reactive

    View Slide

  108. Factory

    View Slide

  109. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just Emitting existing value
    Flowable.defer Flux.defer Lazy emitting
    Flowable.fromCallable Mono.fromCallable
    Lazy emitting, computed from
    a method call
    Flowable.create Flux.create Manual emitting
    Flowable.using Flux.using Resource management
    Flowable.fromPublisher Flux.from
    Using a Publisher (Reactive
    Streams)
    Flowable.generate Flux.generate Using a value generator

    View Slide

  110. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just Emitting existing value
    Flowable.defer Flux.defer Lazy emitting
    Flowable.fromCallable Mono.fromCallable
    Lazy emitting, computed from
    a method call
    Flowable.create Flux.create Manual emitting
    Flowable.using Flux.using Resource management
    Flowable.fromPublisher Flux.from
    Using a Publisher (Reactive
    Streams)
    Flowable.generate Flux.generate Using a value generator

    View Slide

  111. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just Emitting existing value
    Flowable.defer Flux.defer Lazy emitting
    Flowable.fromCallable Mono.fromCallable
    Lazy emitting, computed from
    a method call
    Flowable.create Flux.create Manual emitting
    Flowable.using Flux.using Resource management
    Flowable.fromPublisher Flux.from
    Using a Publisher (Reactive
    Streams)
    Flowable.generate Flux.generate Using a value generator

    View Slide

  112. RxJava

    RxJava 2
    Reactor
    Flowable.just Flux.just Emitting existing value
    Flowable.defer Flux.defer Lazy emitting
    Flowable.fromCallable Mono.fromCallable
    Lazy emitting, computed from
    a method call
    Flowable.create Flux.create Manual emitting
    Flowable.using Flux.using Resource management
    Flowable.fromPublisher Flux.from
    Using a Publisher (Reactive
    Streams)
    Flowable.generate Flux.generate Using a value generator

    View Slide

  113. example of
    wrapping

    View Slide

  114. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }

    View Slide

  115. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }

    View Slide

  116. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }

    View Slide

  117. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {

    CountDownLatch latch = new CountDownLatch(1);

    AtomicReference result = new AtomicReference<>();

    this.connection.subscribe((message, pattern) -> {

    result.set(message.toString());

    latch.countDown();

    }, TOPIC_NAME);

    latch.await();

    return result.get();

    }
    }
    Code for synchronisation
    Code for synchronisation

    View Slide

  118. Step 1 

    Wrapping

    View Slide

  119. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {


    String result = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .blockingFirst();

    return result;

    }
    }

    View Slide

  120. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private String redis() throws InterruptedException {


    String result = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .blockingFirst();

    return result;

    }
    }
    Wrapping
    Synchronisation
    Reactive Contract

    View Slide

  121. Step 2
    Asynchronous

    View Slide

  122. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private DeferredResult redis() throws InterruptedException {


    DeferredResult result = new DeferredResult<>(10_000l);


    Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .subscribe(result::setResult);


    return result;

    }

    View Slide

  123. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis")

    private DeferredResult redis() throws InterruptedException {


    DeferredResult result = new DeferredResult<>(10_000l);


    Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> {

    sub.onNext(message.toString());

    sub.onComplete();

    }, TOPIC_NAME);

    }, BackpressureStrategy.BUFFER)

    .subscribe(result::setResult);


    return result;

    } Lazy result
    Use of DeferredResult

    View Slide

  124. Step 3 

    Reactive Streams

    View Slide

  125. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Flux redis() throws InterruptedException {


    Flowable rxjava = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    return Flux.defer(() -> rxjava);

    }
    }

    View Slide

  126. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Flux redis() throws InterruptedException {


    Flowable rxjava = Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    return Flux.defer(() -> rxjava);

    }
    }
    RxJava 2 → Flux
    Flux → SSE
    Return a Flux

    View Slide

  127. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Publisher redis() throws InterruptedException {

    return Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    }

    View Slide

  128. @RestController

    public class HelloController {


    private static final byte[] TOPIC_NAME = "topic".getBytes();


    @RequestMapping(value = "/redis", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

    private Publisher redis() throws InterruptedException {

    return Flowable.create(sub -> {

    this.connection.subscribe((message, pattern) -> sub.onNext(message.toString()),
    TOPIC_NAME);

    }, BackpressureStrategy.BUFFER);


    }
    Publisher

    View Slide

  129. View Slide

  130. Reactor use Java 8
    while RxJava 2 use
    Java 6

    View Slide

  131. Reactor use Java 8
    while RxJava 2 use
    Java 6

    View Slide

  132. Asynchronous
    Execution context management

    View Slide

  133. Schedulers
    Rethink cette partie là

    View Slide

  134. Scheduler 

    (Thread Pool)
    Task 1
    Task 2
    Task 3
    Task 4

    View Slide

  135. Task 1
    Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  136. Task 1 Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  137. Task 1 Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  138. Task 1 Task 2
    Task 3 Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  139. Task 1
    Task 2
    Task 3 Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  140. Task 1
    Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  141. Task 1
    Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  142. Task 1
    Task 2
    Task 3
    Task 4
    Scheduler 

    (Thread Pool)

    View Slide

  143. java.lang.IllegalStateException: 

    Not on the main thread
    NetworkOnMainThreadException

    View Slide

  144. JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(Schedulers.computation())

    .flatMap(data -> intensiveComputation(data))

    .observeOn(javaFx())

    .doOnNext(value -> btn.setText("Data: " + value)) 

    .subscribe();

    View Slide

  145. JavaFx.fromClick(btn) 

    .observeOn(Schedulers.io())

    .switchMap(evt -> remoteApi.getData())

    .observeOn(Schedulers.computation())

    .flatMap(data -> intensiveComputation(data))

    .observeOn(javaFx())

    .doOnNext(value -> btn.setText("Data: " + value)) 

    .subscribe();
    i/o
    computation
    UI Thread

    View Slide

  146. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Thread pool which
    grow up if needed
    computation() computation() parallel() Limited thread pool
    single() single() single() Pool of 1 thread
    immediate() immediate()
    Execute the task
    immediately
    trampoline() trampoline()
    Queue the current
    task

    View Slide

  147. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Thread pool which
    grow up if needed
    computation() computation() parallel() Limited thread pool
    single() single() single() Pool of 1 thread
    immediate() immediate()
    Execute the task
    immediately
    trampoline() trampoline()
    Queue the current
    task

    View Slide

  148. RxJava RxJava 2 Reactor Description
    io() io() elastic()
    Thread pool which
    grow up if needed
    computation() computation() parallel() Limited thread pool
    single() single() single() Pool of 1 thread
    immediate() immediate()
    Execute the task
    immediately
    trampoline() trampoline()
    Queue the current
    task

    View Slide

  149. Reactor
    Technical naming

    View Slide

  150. RxJava
    Functional naming

    View Slide

  151. Performance

    View Slide

  152. Generation
    3 4 5+
    Fusion
    RxJava 2
    Reactor

    View Slide

  153. Warning
    Conceptuel slides

    View Slide

  154. Without fusion

    View Slide

  155. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  156. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  157. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  158. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  159. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  160. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  161. With fusion

    View Slide

  162. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  163. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  164. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  165. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  166. Transform (
    ⬛ → ⃝ )
    Transform ( ⃝ →
    ⬛)

    View Slide

  167. Fusion
    decreases
    memory consumption and
    increases
    performances

    View Slide

  168. for (int x = 0; x < 10_000; x++) {


    Observable.interval(10, TimeUnit.MILLISECONDS)

    .takeWhile(i -> take.get())

    .flatMap(i -> Observable.range(1, 100))

    .subscribe();

    }

    View Slide

  169. RxJava 2 RxJava
    Reactor

    View Slide

  170. http://akarnokd.blogspot.fr/2016/12/the-reactive-scrabble-benchmarks.html
    Java 8 Stream
    RxJava 2 / Reactor
    RxJava
    December 2016

    View Slide

  171. Java 8 Stream
    RxJava 2 / Reactor
    RxJava
    https://twitter.com/akarnokd/status/844555409012740096
    March 2017

    View Slide

  172. Ecosystem

    View Slide

  173. RxJava RxJava 2 Reactor
    Retrofit Yes Yes No
    RxAndroid Yes Yes No
    Realm Yes No No
    Hystrix Yes No No
    Couchbase Yes No No
    MongoDB Yes No No
    Spring Data 2.0 Yes No Yes
    Reactor IPC No No Yes
    WebFlux No Yes Yes
    Android Spring

    View Slide

  174. RxJava RxJava 2 Reactor
    Retrofit Yes Yes No
    RxAndroid Yes Yes No
    Realm Yes No No
    Hystrix Yes No No
    Couchbase Yes No No
    MongoDB Yes No No
    Spring Data 2.0 Yes No Yes
    Reactor IPC No No Yes
    WebFlux No Yes Yes
    Android Spring

    View Slide

  175. We are aggressively 

    migrating our internal code to
    RxJava 2
    https://github.com/uber/AutoDispose

    View Slide

  176. RxJava RxJava 2 Reactor
    Retrofit Yes Yes No
    RxAndroid Yes Yes No
    Realm Yes No No
    Hystrix Yes No No
    Couchbase Yes No No
    MongoDB Yes No No
    Spring Data 2.0 Yes No Yes
    Reactor IPC No No Yes
    WebFlux No Yes Yes
    Android Spring

    View Slide

  177. Inertia
    to migrate

    View Slide

  178. RxJava RxJava 2 Reactor
    Retrofit Yes Yes No
    RxAndroid Yes Yes No
    Realm Yes No No
    Hystrix Yes No No
    Couchbase Yes No No
    MongoDB Yes No No
    Spring Data 2.0 Yes No Yes
    Reactor IPC No No Yes
    WebFlux No Yes Yes
    Android Spring

    View Slide

  179. Spring 5 will accelerate
    the adoption of Reactor

    View Slide

  180. Android
    RxJava 2

    View Slide

  181. Backend
    RxJava 2

    View Slide

  182. Spring
    Reactor

    View Slide

  183. Thanks for your attention
    We stay in touch?
    [email protected]
    @dwursteisen
    http://blog.soat.fr
    Post your question on sli.do
    ( #K100 )

    View Slide