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

SpringOnePlatform 2017 Reactor Now and Tomorrow

SpringOnePlatform 2017 Reactor Now and Tomorrow

Stephane Maldini

December 06, 2017
Tweet

More Decks by Stephane Maldini

Other Decks in Programming

Transcript

  1. © Copyright 2017 Pivotal Software, Inc. All rights Reserved. Version

    1.0 Stéphane MALDINI Simon BASLÉ Project Reactor Now & Tomorrow SpringOne Platform 2017
  2. Stéphane Maldini Senior Product Manager & Lead Engineer Project Reactor,

    Pivotal & @smaldini Simon Baslé @simonbasle Staff Software Engineer Project Reactor, Pivotal
  3. Now 3.0 → 3.1

  4. Is this a big deal ? Spoiler: yes

  5. Reactor 3.0 Versioning scheme: ERA.MAJOR.MINOR Production ready, but had to

    be out before Spring Framework 5 Still room for evolution after plenty of feedback
  6. Project ____ Downloads : > 300k/month projectreactor.io : > 30k

    unique/month Gitter.im : #7 Java channel
  7. Project ____ 452 Closed Pull Requests 487 Closed Issues 11

    Releases 53 Contributors 4 (+2) Core Committers
  8. Shoutout to our Contributors

  9. Why users want Reactor ?

  10. Why users want Reactor ? Reactive Streams sample extract reactive-streams.org

  11. Why users want Reactor ? Flux.range(from, count)

  12. Do you speak Reactive Streams ?

  13. Reactor and Reactive Streams

  14. Publisher<T> & Subscriber<T>

  15. Publisher<Music>

  16. Subscriber<Music>

  17. Publisher<T> void subscribe(Subscriber<T>)

  18. Subscriber<T> void onNext(T) void onComplete() void onError(Throwable)

  19. Subscription [Music]

  20. Subscription void request(long) void cancel()

  21. Subscriber<T> void onSubscribe(Subscription) void onNext(T) void onComplete() void onError(Throwable)

  22. This is Flow Control

  23. Flux 0-N elements “classic” Publisher

  24. None
  25. Mono 0-1 elements “specialized” Publisher

  26. None
  27. String res; for(int i = 1; i <= 1000; i++)

    { res = blockingHttpGet(“/quote/”+i); handleBody(res); } Without --------
  28. String res; for(int i = 1; i <= 1000; i++)

    { res = blockingHttpGet(“/quote/”+i); handleBody(res); } 1000 calls later... Main Thread Without --------
  29. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i)) .subscribe(this::handleBody); With --------

  30. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i)) .subscribe(this::handleBody); operator With --------

  31. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i)) .subscribe(this::handleBody); 1 call later Main

    Thread With --------
  32. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i)) .subscribe(this::handleBody); 256 http calls With

    --------
  33. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i), 1) .subscribe(this::handleBody); With -------- 1

    http call
  34. Flux.range(1, 1000) .flatMap(i -> reactiveHttpCall("/quote/"+i), 1) .subscribe(this::handleBody); With -------- J-j-jeez

    Rick, I like this backpressure stuff 1 http call
  35. At every stage, Flux and Mono are Publisher

  36. interface SomeReactiveApi { Flux<T> findUsersLike(Publisher<String> usernames) } //... someReactiveApi.findUsersLike(Mono.just(“ricksanchez”)) .subscribe(handleUsers);

    Everywhere
  37. interface SomeReactiveApi { Flux<T> findUsersLike(Publisher<String> usernames) } //... someReactiveApi.findUsersLike(Mono.just(“ricksanchez”)) .subscribe(handleUsers);

    //or someReactiveApi.findUsersLike(someFlux.filter(“sanchez”::endsWith)) .subscribe(handleUsers); Everywhere
  38. interface SomeReactiveApi { Flux<T> findUsersLike(Publisher<String> usernames) } //... someReactiveApi.findUsersLike(Mono.just(“ricksanchez”)) .subscribe(handleUsers);

    //or someReactiveApi.findUsersLike(someFlux.filter(“sanchez”::endsWith)) .subscribe(handleUsers); Everywhere Look Morty, the universe wants API consistency !
  39. Reactor Core 3.1 Hot from the oven

  40. 3.0 → LTS 3.1

  41. 3.1 is a polished programming experience

  42. Flux Mono Aligning APIs between Flux and Mono

  43. Flux Mono flatmap then

  44. Flux Mono flatmap then

  45. Flux Mono flatmap flatmap

  46. None
  47. Practical static extensions Initial N ullability support

  48. “Reactor has matured, laying out the foundations for frameworks and

    users to integrate their context into the Core .” Enterprise Ready: Hooks & Customization, Matured API
  49. Cross-Cutting Concerns

  50. Scannable Visit the hierarchy of operators Scan at each step

    for Attributes... … either upstream (parents()) or downstream (actuals())
  51. Tagging and Naming give a chain of operator a name

    give a chain of operator attributes
  52. Tagging and Naming Flux.range(1, 10) .name("myRange") .tag("createdBy", "rick");

  53. Hooks On last operator instantiation before subscribe On every operator

    instantiation
  54. Hooks.onLastOperator( Operators.lift(scannable -> scannable.tags() .anyMatch(t -> t.getT1() .contains("createdBy")), (scannable, subscriber)

    -> { fooService.registerOwnedFlux(scannable); return subscriber; })); Hooks
  55. Hooks.onLastOperator( Operators.lift(scannable -> scannable.tags() .anyMatch(t -> t.getT1() .contains("createdBy")), (scannable, subscriber)

    -> { fooService.registerOwnedFlux(scannable); return subscriber; })); Hooks Once every stream... Only visit streams containing tag... Notify some service with the stream reference and return the operator subscriber
  56. Possible Application: Metrics E.g. tag a Flux with “METRICS” and

    a framework could pick that up and add an operator that increments counters/timers...
  57. Improved Testing Support

  58. reactor-test StepVerifier to assert expectations on any Publisher TestPublisher to

    simulate a reactive source PublisherProbe to check which path was used in complex chains
  59. StepVerifier StepVerifier.withVirtualTime( () -> Flux.interval(Duration.ofSeconds(45)).take(2)) .thenAwait(Duration.ofSeconds(50)) .expectNext(0L) .thenAwait(Duration.ofSeconds(40)) .assertNext(v ->

    assertThat(v).isGreaterThan(0L)) .expectComplete() .verify();
  60. TestPublisher TestPublisher.create() .next(1, 2, 3, 4) .complete(); TestPublisher.createNonCompliant(Violation.ALLOW_NULLS) .emit(1, 2,

    3, null, 4); next() + complete()
  61. PublisherProbe probe = PublisherProbe.of(Flux.range(1, 10)); reactiveConditionalPath(Mono.just(1), probe.flux()) .subscribe(); probe.assertWasSubscribed(); PublisherProbe

  62. The Context

  63. Immutable Context a = Context.of(“key”, “value”); Context b = a.put(“key”,

    “value2”); a.get(“key”); // ⇒ “value” b.get(“key”); // ⇒ “value2”
  64. Propagates during Subscription [a=2,b=2] [a=1,b=2] [] ctx.put(b,2) [a=1] ctx.put(a,1) )

    subscribe( Subscriber Subscribe & Context Data ctx.put(a,2)
  65. See Reference Guide for Snippets like this: String key =

    "message"; Mono<String> r = Mono.just("Hello") .subscriberContext(ctx -> ctx.put(key,"World")) .flatMap( s -> Mono .subscriberContext() .map(ctx -> s + " " + ctx.getOrDefault(key, "Stranger")) ); StepVerifier.create(r) .expectNext("Hello Stranger") .verifyComplete();
  66. More about Bismuth Release https://spring.io/blog/2017/09/28/reactor-bismuth-is-out Executive summary of latest 3.1

    additions
  67. What’s new in The Ecosystem ? In-house or community grown

    initiatives
  68. reactor-netty

  69. Reactor Netty only turns Netty into a Reactive Streams ready

    bridge
  70. Just a few threads for a production-ready volume of connections

    with various latencies write read select worker worker worker
  71. Non Blocking TCP, UDP and HTTP Decouples Read and Write

    Pauses reading on local Backpressure Pauses local producing on Backpressure
  72. Webflux WebClient Cloud Gateway Boot 2.0 Used and Distributed by

    Spring
  73. Vendor warning

  74. Reactor Netty 0.7 API

  75. Reactor Netty 0.7 API

  76. Seriously, it’s 0.7.2. It runs well. But we’re polishing API

    before 0.8.0.M1 Best to use--------
  77. reactor-kafka

  78. Publish & Consume messages from Kafka... … with a backpressure-ready

    Reactive API https://github.com/reactor/reactor-kafka Reactor-Kafka
  79. Reactor-Kafka KafkaSender.create() .send(Flux.range(1, 10) .map(i -> SenderRecord.create(topic, partition, timestamp, i,

    "msg_" + i,i))) .subscribe();
  80. reactor-rabbitmq

  81. Reactor-RabbitMQ Publish & Consume messages from RabbitMQ... … with a

    backpressure-ready Reactive API https://github.com/reactor/reactor-rabbitmq
  82. Reactor-RabbitMQ Flux<Delivery> inboundFlux = ReactorRabbitMq.receiver(receiverOptions) .consumeNoAck("reactive.queue") .subscribe(messageHandler);

  83. reactor-addons

  84. Reactor-Addons Extend Reactor Core API Adapt Reactor to different execution

    contracts https://github.com/reactor/reactor-addons
  85. Retry Support Factory methods that provide a fluent API to

    incrementally configure a Function suitable for Flux.retryWhen. (tip: use static import) Retry.allBut(Class<Exception>...) Retry.any() Retry.anyOf(Class<Exception>...) Retry.onlyIf(Predicate)
  86. Retry Support flux.retryWhen(allBut(BusinessException.class) .retryMax(3) .exponentialBackoff(Duration.ofMillis(100), Duration.ofMillis(500)) .timeout(Duration.ofMillis(1500)) .jitter(Jitter.random()) .doOnRetry(this::retryCallback) );

  87. Math Take a Flux<Number> and apply operations to its whole

    set of elements using MathFlux static methods. Mono<Long> sum = Flux.range(1, 10) .as(MathFlux::sumLong);
  88. Math (with kotlin) Mono<Long> sum = Flux.range(1, 10) .sumLong();

  89. An opinionated abstraction that helps you store and lookup a

    Mono or a Flux to/from a cache. CacheMono will store the Mono value or completion as a Signal. CacheFlux will collect the elements and terminal event as a List<Signal>. Both only work with finite sources. Cache Support
  90. Mono<Integer> test = CacheMono.lookup(reader(data), "foo") .onCacheMissResume(() -> Mono.just(1L)) .andWriteWith(writer(data)); Reader

    and writer interfaces to adapt to any type of cache implementation + out-of-the-box variant for Map. Cache Support
  91. Community Highlights

  92. Spring Ecosystem #1 user and source of feedback

  93. None
  94. None
  95. Reactive talk with

  96. None
  97. reactive-gRPC https://github.com/salesforce/reactive-grpc Integrates reactive programming with grpc-java From --

  98. Lettuce http://lettuce.io A Reactor-based reactive driver for Redis

  99. Tech.io https://tech.io/playgrounds/929/reactive-programming-with-reactor-3 A community-driven programming learning platform

  100. CloudFoundry Java Client https://github.com/cloudfoundry/cf-java-client The official Java client for CloudFoundry

    API
  101. https://github.com/reactor/reactor-scala-extensions Idiomatic Scala for Reactor

  102. Reactor Tomorrow Near-and-far Future<T>

  103. Near-and-far Future<T> Reactor Tomorrow

  104. Reactor Tomorrow Near-and-far future

  105. 2019 2020 2017 2018 the Road from Here

  106. 2017 First, a patch release

  107. 3.1.3 3.1.0 September October November December 3.1.1 3.1.2

  108. 3.1.3 3.1.0 September October November December 3.1.1 3.1.2 limitRequest, Kotlin

    extensions...
  109. 3.1.3 3.1.0 September October November December 3.1.1 3.1.2 index, blockOptional...

  110. 3.1.3 3.1.0 September October November December 3.1.1 3.1.2 Mostly bugfixes...

  111. 2018 Themes for

  112. Continue On Error

  113. errors are terminal

  114. continue on (transient) errors?

  115. Now Flux.range(0, 3) .flatMap(v -> Mono.just(v) .map(i -> 100 /

    i) .doOnError(...) .onErrorResume( Mono.empty() ) ); processing that can fail your face when you read this code
  116. Tomorrow Flux.range(0, 3) .map(i -> 100 / i) .errorStrategyContinue() .filter(i

    -> 100 / i > 4); this is not impacted and can still fail this is protected by this
  117. Observability & Traceability

  118. Micrometer “SLF4J for metrics”

  119. Sleuth & Zipkin Currently focusing on tracing WebFlux and WebClient

    any guess as to why these are different? flatMap concatMap
  120. reactor-netty

  121. API iteration release : 0.8.x Immutable server and client builders

    Lifecycle and interceptor API (doOnRequest...) Initial user guide
  122. API iteration release : 0.8.x HttpClient.prepare() .port(c.address().getPort()) .wiretap() .get() .uri("/test/test.css")

    .responseContent() .asString() .reduce(String::concat) .subscribe(System.out::println);
  123. Beyond 0.8 HTTP 2 support Plug-And-Play Metrics Connection Pool improvements

    Backpressure strategies
  124. File I/O Addon?

  125. Java 9 continuously improve support

  126. Java 9 continuously improve support RSocket

  127. Exploring RSocket (rsocket.io) Duplex flow-control support Multi-transport and multi-language Decoupled

    from any serialization Contributors from Facebook
  128. Beyond and

  129. Reactor Kore?

  130. Reactor Console?

  131. ADBA ?

  132. Just Wondering Flux Buffers Lifecycle Hooks ? Persistent Flux ?

    Coordinated demand ?
  133. None
  134. What do you need ?

  135. The end Thank You!