Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Reactor, Reactive streams and MicroServices

5,392 views

Published on

A 1h intro to Reactive Streams relationship with Reactor and how it fits into MicroService

Published in: Software
  • Login to see the comments

Reactor, Reactive streams and MicroServices

  1. 1. Reactor, Reactive Streams and the MicroService architecture Stephane Maldini © Copyright 2013 Pivotal. All rights reserved. ‹‹#››
  2. 2. ‹#› @smaldini - solve 9 issues, create 10 problems Customer Success Organization @ Pivotal Reactor Committer II Try to contribute to Reactive-Streams
  3. 3. ‹#›
  4. 4. ‹#› NanoService, MicroService, NotTooBigService™… Aperture Sciences Test 981: Observe the following examples
  5. 5. ‹#› NanoService, MicroService, NotTooBigService™… cat file.csv
  6. 6. ‹#› NanoService, MicroService, NotTooBigService™… cat file.csv | grep ‘doge’
  7. 7. ‹#› NanoService, MicroService, NotTooBigService™… cat file.csv | grep ‘doge’ | sort
  8. 8. ‹#› NanoService, MicroService, NotTooBigService™… POST [json] http://dogecoin.money/send/id
  9. 9. ‹#› NanoService, MicroService, NotTooBigService™… POST [json] http://dogecoin.money/send/id —> GET [json] http://dogeprofile.money/id
  10. 10. ‹#› NanoService, MicroService, NotTooBigService™… POST [json] http://dogecoin.money/send/id —> GET [json] http://dogeprofile.money/id —> POST [json] http://nsa.gov.us/cc/trace/id
  11. 11. ‹#› NanoService, MicroService, NotTooBigService™… userService.auth(username,password)
  12. 12. ‹#› NanoService, MicroService, NotTooBigService™… userService.auth(username,password) —> userService.hashPassword(password)
  13. 13. ‹#› NanoService, MicroService, NotTooBigService™… userService.auth(username,password) —> userService.hashPassword(password) —> userService.findByNameAndHash(name)
  14. 14. ‹#› NanoService, MicroService, NotTooBigService™… • A SomethingService will always need to interact • With the user • With other services • The boundary between services is the real deal
  15. 15. ‹#› And this threat has a name
  16. 16. ‹#› And this threat has a name Latency
  17. 17. ‹#› UberFact : Humans don’t really enjoy waiting
  18. 18. ‹#› UberFact : Humans don’t really enjoy waiting Neither do The Machines
  19. 19. ‹#› What is latency doing to you ? • Loss of revenues • because users switched to another site/app • because services are compounding inefficiency • because aggressive scaling will be needed
  20. 20. ‹#› What is latency doing to you ? • Loss of revenues • because users switched to another site/app • because services are compounding inefficiency • because aggressive scaling will be needed ‘2 bucks prediction’ : tech team turnover will increase and keep mourning about how crap is their design
  21. 21. ‹#› Loading
  22. 22. ‹#› Loading
  23. 23. ‹#› All hail Reactive Programming • A possible answer to this issue • The very nature of Reactor, look at the name dude • A fancy buzz-word that might work better than MDA or SOA • A simple accumulation of years of engineering
  24. 24. ‹#› No sh*t, what is Reactive Programming ?
  25. 25. ‹#› No sh*t, what is Reactive Programming ? Event-Driven
  26. 26. ‹#› No sh*t, what is Reactive Programming ? Event-Driven Fault-Tolerant
  27. 27. ‹#› No sh*t, what is Reactive Programming ? Event-Driven Fault-Tolerant Scalable
  28. 28. ‹#› No sh*t, what is Reactive Programming ? Event-Driven Fault-Tolerant Low-latency* Scalable
  29. 29. ‹#› Reactive Architecture ? • A Reactive system MUST be resilient –splitting concerns to achieve error bulk-heading and modularity • A Reactive system MUST be scalable – scale-up : partition work across CPUs – scale-out : distribute over peer nodes
  30. 30. ‹#› Reactor has 99 problems but Latency isn’t one
  31. 31. ‹#› Reactor-Core features 17
  32. 32. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers
  33. 33. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers Event Bus [Reactor.class]
  34. 34. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers Event Bus [Reactor.class] Streams and Promises
  35. 35. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers Event Bus [Reactor.class] Streams and Promises Functional artifacts (SAM components, tuples, timers)
  36. 36. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers Event Bus [Reactor.class] Streams and Promises Functional artifacts (SAM components, tuples, timers) Fast IO [buffer, net, persistent queues, codec]
  37. 37. ‹#› Reactor-Core features 17 [A]synchronous Dispatchers Event Bus [Reactor.class] Streams and Promises Functional artifacts (SAM components, tuples, timers) Fast IO [buffer, net, persistent queues, codec] Fast Data [allocators, batch-processors]
  38. 38. ‹#› Stream?
  39. 39. ‹#› Stream
  40. 40. ‹#› Stream!
  41. 41. ‹#› Stream!
  42. 42. ‹#› Using a Stream ? import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge')
  43. 43. ‹#› import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge') Prepare a simple Stream Using a Stream ?
  44. 44. ‹#› import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge') Prepare a simple Stream 1st step Using a Stream ?
  45. 45. ‹#› import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge') Prepare a simple Stream 1st step 2nd step Using a Stream ?
  46. 46. ‹#› import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge') Prepare a simple Stream 1st step 2nd step Terminal callback Using a Stream ?
  47. 47. ‹#› Using a Stream ? import reactor.rx.spec.Streams def stream = Streams.defer() stream.map{ name -> Tuple.of(name, 'so wow') }.map{ tuple -> Tuple.of(tuple.t1, "$tuple.t2, much sad") }.consume{ tuple -> println "bye bye ! $tuple.t2... $tuple.t1" } stream.broadcastNext('Doge') Prepare a simple Stream 1st step 2nd step Terminal callback Send some data into the stream
  48. 48. ‹#› Using a Stream ? Embedded data-processing Event Processing Metrics, Statistics Micro-Batching Composition Error Handling
  49. 49. ‹#› Defining a Stream • Represents a sequence of data, possibly unbounded • Provide for processing API such as filtering and enrichment • Not a Collection, not a Storage
  50. 50. ‹#› Stream VS Event Bus [Reactor] • Works great combined (stream distribution) • Type-checked flow • Publisher/Subscriber tight control • No Signal concurrency
  51. 51. ‹#› Stream VS Event Bus [Reactor] • Works great combined (stream distribution) • Type-checked flow • Publisher/Subscriber tight control • No Signal concurrency Rule of thumb: if nested event composition > 2, switch to Stream
  52. 52. ‹#› Hot Stream vs Cold Stream • An Hot Stream multi-casts real-time signals –think Trade, Tick, Mouse Click, Websocket • A Cold Stream uni-casts deferred signals –think File, Array, Computation result (Future)
  53. 53. ‹#› Reactor : Iterable Cold Stream Streams .just(1, 2, 3, 4, 5) .take(3) .subscribe(System.out::println);
  54. 54. ‹#› Reactor : AMQP Hot Stream LapinStreams .fromQueue(queueName) .dispatchOn(Environment.get()) .timeout(30) .subscribe(System.out::println);
  55. 55. ‹#› Reactor : AMQP Hot Stream COMING SOON IN A REPOSITORY NEAR YOU LapinStreams .fromQueue(queueName) .dispatchOn(Environment.get()) .timeout(30) .subscribe(System.out::println);
  56. 56. ‹#› Introducing Reactive Streams Specification !
  57. 57. ‹#› What is defined by Reactive Streams ?
  58. 58. ‹#› What is defined by Reactive Streams ? Async non-blocking data sequence
  59. 59. ‹#› What is defined by Reactive Streams ? Async non-blocking data sequence Minimal resources requirement
  60. 60. ‹#› What is defined by Reactive Streams ? Interoperable protocol Async non-blocking data sequence (Threads, Nodes…) Minimal resources requirement
  61. 61. ‹#› What is defined by Reactive Streams ? Async non-blocking flow-control Interoperable protocol Async non-blocking data sequence (Threads, Nodes…) Minimal resources requirement
  62. 62. ‹#› Reactive-Streams: Dynamic Message-Passing
  63. 63. ‹#› Reactive-Streams: Dynamic Message-Passing PUBLISHER
  64. 64. ‹#› Reactive-Streams: Dynamic Message-Passing PUBLISHER SUBSCRIBER
  65. 65. ‹#› Reactive-Streams: Dynamic Message-Passing PUBLISHER SUBSCRIBER
  66. 66. ‹#› Reactive-Streams: Dynamic Message-Passing PUBLISHER SUBSCRIBER Events
  67. 67. ‹#› Reactive-Streams: Dynamic Message-Passing PUBLISHER SUBSCRIBER Events Demand
  68. 68. ‹#› Now You Know • It is not only queue-based pattern: – Signaling demand on a slower Publisher == no buffering – Signaling demand on a faster Publisher == buffering • Data volume is bounded by a Subscriber – Scaling dynamically if required
  69. 69. ‹#› Out Of The Box : Flow Control
  70. 70. ‹#› Out Of The Box : Flow Control PUBLISHER
  71. 71. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER
  72. 72. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER
  73. 73. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER Slow SUBSCRIBER
  74. 74. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER Slow SUBSCRIBER
  75. 75. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER Slow SUBSCRIBER
  76. 76. ‹#› Out Of The Box : Flow Control PUBLISHER SUBSCRIBER Slow Fast SUBSCRIBER
  77. 77. ‹#› Reactive Streams: Signals onError | (onSubscribe onNext* (onError | onComplete)?)
  78. 78. ‹#› Reactive Streams: Joining forces ccv Doug Lea – SUNY Oswego
  79. 79. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  80. 80. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  81. 81. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  82. 82. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  83. 83. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  84. 84. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  85. 85. ‹#› Reactive Streams: Joining forces Reactor Data Driver Akka Distributed System RxJava Metrics Pipeline Ratpack HTTP server
  86. 86. ‹#› Reactive Streams: An industrial matured spec • Semantics – Single document listing full rules – Open enough to allow for various patterns • 4 API Interfaces – Publisher, Subscriber, Subscription, Processor • TCK to verify implementation behavior
  87. 87. ‹#› Reactive Streams: org.reactivestreams public interface Publisher<T> { public void subscribe(Subscriber<T> s); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscription { public void request(int n); public void cancel(); }
  88. 88. ‹#› Reactive Streams: org.reactivestreams public interface Publisher<T> { public void subscribe(Subscriber<T> s); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscription { public void request(int n); public void cancel(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {}
  89. 89. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  90. 90. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  91. 91. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  92. 92. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  93. 93. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  94. 94. ‹#› Reactor <=> Reactive Streams Publisher reactor.rx.Stream Subscriber reactor.rx.actions.Action Processor reactor.rx.Promise
  95. 95. ‹#›
  96. 96. ‹#› What about RxJava mate ! All those hipsters use it.
  97. 97. ‹#› Reactor == RxJava • Reactor Streams 2.0 are inspired by Rx and RxJava • http://msdn.microsoft.com/en-gb/data/gg577609.aspx • Naming and behavior is mostly aligned with RxJava (just, flatMap, retry…) • Rx Patterns should apply to Reactor Streams • Lightweight, embeddable
  98. 98. ‹#› Reactor != RxJava • Reactor Streams mission: • Data throughput over Functional facilities (Dispatchers, Subscription model, pre-allocation) • Pivotal integration (Spring.io, RabbitMQ, Redis, CloudFoundry, Gemfire…) • Native Reactive Streams, all Stream actions benefit from back pressure model and can talk to any implementation
  99. 99. ‹#› slidesSubscription.request(18); //talkSubscription.cancel();
  100. 100. ‹#›
  101. 101. ‹#› Let’s finish with practical patterns to empower your Reactive Service
  102. 102. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher4) dispatchOn(dispatcher1) disp[..] disp[..] httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 R2 R3 Resource #4
  103. 103. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher4) dispatchOn(dispatcher1) disp[..] disp[..] Not that efficient httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 R2 R3 Resource #4
  104. 104. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher14) dispatchOn(dispatcher1) httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 Resource #4
  105. 105. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher14) dispatchOn(dispatcher1) Non Blocking Stream until last callback httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 Resource #4
  106. 106. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher1) dispatchOn(dispatcher2) httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 Resource #2
  107. 107. ‹#› Reactive Streams: Async Boundaries dispatchOn(dispatcher1) dispatchOn(dispatcher2) httpRequestStream map(f) filter(p) consume(httpResponseConsumer) Resource #1 Resource #2 81,2% OK, producer not blocked
  108. 108. ‹#› A full slide just to say something about FlatMap
  109. 109. ‹#› A full slide just to say something about FlatMap FlatMap Bucket Challenge ! Nominate 3 friends to explain flatMap()
  110. 110. ‹#› Another one, FlatMap is that cool
  111. 111. ‹#› Another one, FlatMap is that cool flatMap() is nothing more than the functional alternative to RPC. Just a way to say “Ok bind this incoming data to this sub-flow and listen for the result, dude”.
  112. 112. ‹#› Another one, FlatMap is that cool
  113. 113. ‹#› Another one, FlatMap is that cool Usually in Functional Reactive Programming, flatMap is often used for crossing an async boundary.
  114. 114. ‹#› Another one, FlatMap is that cool
  115. 115. ‹#› Another one, FlatMap is that cool This applies to Reactor too, but ALL Reactor actions also have built-in backpressure support and dispatching facilities
  116. 116. ‹#› Before you miss it, a FlatMap example Streams.just('doge’).flatMap{ name -> Streams.just(name) .observe{ println 'so wow' } .map{ 'much monad'} }.consume{ assert it == 'much monad' }
  117. 117. ‹#› Before you miss it, a FlatMap example Streams.just('doge’).flatMap{ name -> Streams.just(name) .observe{ println 'so wow' } .map{ 'much monad'} }.consume{ assert it == 'much monad' } Feed a dynamic Sub-Stream with a name
  118. 118. ‹#› Streams.just('doge’).flatMap{ name -> Streams.just(name) .observe{ println 'so wow' } .map{ 'much monad'} }.consume{ assert it == 'much monad' } Feed a dynamic Sub-Stream with a name Sub-Stream definition Before you miss it, a FlatMap example
  119. 119. ‹#› Before you miss it, a FlatMap example Streams.just('doge’).flatMap{ name -> Streams.just(name) .observe{ println 'so wow' } .map{ 'much monad'} }.consume{ assert it == 'much monad' } Feed a dynamic Sub-Stream with a name Sub-Stream definition Sub-Stream result is merged back to the top-level Steam
  120. 120. ‹#› Doing IO work (esp. O) : Cloning Pipeline deferred = Streams.<String>defer(Environment.get()); deferred .parallel(8) .map(stream -> stream .map(i -> i) .reduce(2, service::reducePairAsMap) .consume(service::forwardToOutput) ).drain();
  121. 121. ‹#› Doing IO work (esp. O) : Cloning Pipeline deferred = Streams.<String>defer(Environment.get()); deferred .parallel(8) .map(stream -> stream .map(i -> i) .reduce(2, service::reducePairAsMap) .consume(service::forwardToOutput) ).drain(); Will create 8 clones competing for upstream data
  122. 122. ‹#› Doing IO work (esp. O) : Cloning Pipeline deferred = Streams.<String>defer(Environment.get()); deferred .parallel(8) .map(stream -> stream .map(i -> i) .reduce(2, service::reducePairAsMap) .consume(service::forwardToOutput) ).drain(); Will create 8 clones competing for upstream data Start consuming the full Stream until complete
  123. 123. ‹#› Dealing with a nervous Publisher Streams.range(1, Integer.MAX_VALUE) .dispatchOn(Environment.masterDispatcher()) .sample(2l, TimeUnit.SECONDS) .dispatchOn(Environment.cachedDispatcher()) .consume{ println it }
  124. 124. ‹#› Dealing with a nervous Publisher Streams.range(1, Integer.MAX_VALUE) .dispatchOn(Environment.masterDispatcher()) .sample(2l, TimeUnit.SECONDS) .dispatchOn(Environment.cachedDispatcher()) .consume{ println it } An intense publisher
  125. 125. ‹#› Dealing with a nervous Publisher Assigned with a global dispatcher An intense publisher Streams.range(1, Integer.MAX_VALUE) .dispatchOn(Environment.masterDispatcher()) .sample(2l, TimeUnit.SECONDS) .dispatchOn(Environment.cachedDispatcher()) .consume{ println it }
  126. 126. ‹#› Dealing with a nervous Publisher Assigned with a global dispatcher An intense publisher Streams.range(1, Integer.MAX_VALUE) .dispatchOn(Environment.masterDispatcher()) .sample(2l, TimeUnit.SECONDS) .dispatchOn(Environment.cachedDispatcher()) .consume{ println it } Retaining a single value every 2s
  127. 127. ‹#› Dealing with a nervous Publisher Assigned with a global dispatcher An intense publisher Streams.range(1, Integer.MAX_VALUE) .dispatchOn(Environment.masterDispatcher()) .sample(2l, TimeUnit.SECONDS) .dispatchOn(Environment.cachedDispatcher()) .consume{ println it } Retaining a single value every 2s Dispatching the samples with a different dispatcher to avoid publisher contention
  128. 128. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher
  129. 129. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher
  130. 130. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize
  131. 131. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize window
  132. 132. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize window flatMap
  133. 133. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize window flatMap reduce
  134. 134. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize window flatMap reduce switchOnNext
  135. 135. ‹#› Failproof: Implementing a Circuit Breaker def closeCircuit = stream def openCircuit = fallback ?: Streams.<T>fail(new Exception("service unavailable")) def circuitSwitcher = Streams.switchOnNext() stream .materialize() .window(maxSignals, maxTime) .flatMap{ s -> timer s.reduce(["failures":0, "success":0]){ tuple -> if(tuple.t2.isOnNext()) tuple.t1.success++ else if(tuple.t2.isOnError()) tuple.t1.failures++ } } .consume({ streamHealth -> if(streamHealth.failures/(streamHealth.failures + streamHealth.success) > threshold) { Streams.timer(closeTimeout).consume{ circuitSwitcher.onNext(closeCircuit) } circuitSwitcher.onNext(openCircuit) } else { TL;DR circuitSwitcher.onNext(closeCircuit) } }, circuitSwitcher.&onError, circuitSwitcher.&onComplete) //start with close circuit circuitSwitcher.onNext(closeCircuit) circuitSwitcher materialize window flatMap reduce switchOnNext
  136. 136. ‹#› Failproof: Implementing a Circuit Breaker def fallback = Streams.<String>fail(new Exception("Fast fail") //Open the circuit if there were more than 50% errors over 5 elements or within 3 sec. //Will automatically close the circuit again after 2 sec. Streams.circuitBreaker(stream, fallback, 5, 3, 0.5, 2) .retryWhen{ s -> s.zipWith(Streams.range(1,3)){ tuple.t2 } .flatMap{ Streams.timer(it) } } .consume ( { println it }, { println it.message }, { println errors } )
  137. 137. ‹#› Failproof: Implementing a Circuit Breaker def fallback = Streams.<String>fail(new Exception("Fast fail") //Open the circuit if there were more than 50% errors over 5 elements or within 3 sec. //Will automatically close the circuit again after 2 sec. Streams.circuitBreaker(stream, fallback, 5, 3, 0.5, 2) .retryWhen{ s -> s.zipWith(Streams.range(1,3)){ tuple.t2 } .flatMap{ Streams.timer(it) } } .consume ( { println it }, { println it.message }, { println errors } ) Coming soon™ in M2
  138. 138. ‹#› DEMO [if time left > 1.mn]
  139. 139. ‹#› Featuring…. RabbitMQ Ratpack Reactor Stream Websocket client (RxJS + Angular)
  140. 140. ‹#› Featuring…. RabbitMQ Ratpack Reactor Stream Websocket client (RxJS + Angular)
  141. 141. ‹#› Featuring…. RabbitMQ Ratpack Reactor Stream Websocket client (RxJS + Angular)
  142. 142. ‹#› Featuring…. RabbitMQ Ratpack Reactor Stream Websocket client (RxJS + Angular)
  143. 143. ‹#› Early adopters • Checkpoint –Reactor 2.0.0.M1 implements 0.4.0 - TCK OK –Akka Streams 0.10-M1 implements 0.4.0 - TCK OK –RxJava - ReactiveStreams 0.3.0 implements 0.4.0 - TCK EVALUATED –Ratpack 0.9.9 implements 0.4.0 - TCK OK • Links –https://github.com/Netflix/RxJava –http://typesafe.com/blog/typesafe-announces-akka-streams –https://github.com/reactor/reactor –http://www.ratpack.io/manual/0.9.9/streams.html
  144. 144. ‹#› ReactiveStreams.onSubscribe(Resources) • www.reactive-streams.org • https://github.com/reactive-streams/reactive-streams • on maven central : 0.4.0 – org.reactivestreams/reactive-streams – org.reactivestreams/reactive-streams-tck
  145. 145. ‹#› ReactiveStreams.onNext(Roadmap) • Discussed for inclusion in JDK • Close to release: 1.0.0.M1 – Evaluating TCK before going 1.0 final – Need 3 fully passing implementations before going 1.0.0.M1
  146. 146. ‹#› Reactor.onSubscribe(Resources) • http://projectreactor.cfapps.io/ • https://github.com/reactor • Twitter: @projectReactor • Blog Post: https://spring.io/blog/2014/10/21/reactor-2-0-0-m1- released-with-reactive-streams-integration • on maven central : 2.0.0.M1, 2.0.0.BUILD-SNAPSHOT – org.projectreactor/reactor
  147. 147. ‹#› Q & A
  148. 148. ‹#› session.onComplete()

×