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. 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
  4. Project ____ Downloads : > 300k/month projectreactor.io : > 30k

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

    Releases 53 Contributors 4 (+2) Core Committers
  6. String res; for(int i = 1; i <= 1000; i++)

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

    { res = blockingHttpGet(“/quote/”+i); handleBody(res); } 1000 calls later... Main Thread Without --------
  8. 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
  9. 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 !
  10. “Reactor has matured, laying out the foundations for frameworks and

    users to integrate their context into the Core .” Enterprise Ready: Hooks & Customization, Matured API
  11. Scannable Visit the hierarchy of operators Scan at each step

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

    give a chain of operator attributes
  13. 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
  14. 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...
  15. 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
  16. Immutable Context a = Context.of(“key”, “value”); Context b = a.put(“key”,

    “value2”); a.get(“key”); // ⇒ “value” b.get(“key”); // ⇒ “value2”
  17. 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)
  18. 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();
  19. Just a few threads for a production-ready volume of connections

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

    Pauses reading on local Backpressure Pauses local producing on Backpressure
  21. Publish & Consume messages from Kafka... … with a backpressure-ready

    Reactive API https://github.com/reactor/reactor-kafka Reactor-Kafka
  22. Reactor-RabbitMQ Publish & Consume messages from RabbitMQ... … with a

    backpressure-ready Reactive API https://github.com/reactor/reactor-rabbitmq
  23. Reactor-Addons Extend Reactor Core API Adapt Reactor to different execution

    contracts https://github.com/reactor/reactor-addons
  24. 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)
  25. 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);
  26. 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
  27. 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
  28. 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
  29. 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
  30. Sleuth & Zipkin Currently focusing on tracing WebFlux and WebClient

    any guess as to why these are different? flatMap concatMap
  31. API iteration release : 0.8.x Immutable server and client builders

    Lifecycle and interceptor API (doOnRequest...) Initial user guide
  32. 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);