Futures and Rx Observables: powerful abstractions for consuming web services asynchronously
Upcoming SlideShare
Loading in...5
×
 

Futures and Rx Observables: powerful abstractions for consuming web services asynchronously

on

  • 2,679 views

Speaker: Chris Richardson ...

Speaker: Chris Richardson
A modular, polyglot architecture has many advantages but it also adds complexity since each incoming request typically fans out to multiple distributed services. For example, in an online store application the information on a product details page - description, price, recommendations, etc - comes from numerous services. To minimize response time and improve scalability, these services must be invoked concurrently. However, traditional concurrency mechanisms are low-level, painful to use and error-prone.
In this talk you will learn about some powerful yet easy to use abstractions for consuming web services asynchronously. We will compare the various implementations of futures that are available in Java, Scala and JavaScript. You will learn how to use reactive observables, which are asynchronous data streams, to access web services from both Java and JavaScript. We will describe how these mechanisms let you write asynchronous code in a very straightforward, declarative fashion.

Statistics

Views

Total Views
2,679
Views on SlideShare
2,679
Embed Views
0

Actions

Likes
4
Downloads
31
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Futures and Rx Observables: powerful abstractions for consuming web services asynchronously Futures and Rx Observables: powerful abstractions for consuming web services asynchronously Presentation Transcript

  • Consuming web services asynchronously with Futures and Rx Observables Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com @crichardson
  • Presentation goal Learn how to use (Scala) Futures and Rx Observables to write simple yet robust and scalable concurrent code @crichardson
  • About Chris @crichardson
  • (About Chris) @crichardson
  • About Chris() @crichardson
  • About Chris @crichardson
  • About Chris http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/ @crichardson
  • About Chris @crichardson
  • Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions @crichardson
  • Let’s imagine you are building an online store @crichardson
  • Reviews Product Info Shipping Recomendations @crichardson
  • Product Info Reviews Sales ranking @crichardson
  • Related books Forum Viewing history @crichardson
  • + mobile apps @crichardson
  • Application architecture Desktop browser REST Product Info Service REST Recomendation Service REST Review Service Front end server HTML Mobile browser Native mobile client Web Application REST API gateway @crichardson
  • Handling getProductDetails() Product Info Service getProductInfo() getProductDetails() Front-end server getRecommendations() Recommendations Service getReviews() Review Service @crichardson
  • Handling getProductDetails() - sequentially Product Info Service getProductInfo() getProductDetails() Front-end server getRecommendations() Recommendations Service getReviews() Higher response time :-( Review Service @crichardson
  • Handling getProductDetails() - in parallel Product Info Service getProductInfo() getProductDetails() Front-end server getRecommendations() Recommendations Service getReviews() Lower response time :-) Review Service @crichardson
  • Implementing a concurrent REST client Thread-pool based approach executorService.submit(new Callable(...)) Simpler but less scalable - lots of idle threads consuming memory Event-driven approach NIO with completion callbacks More complex but more scalable @crichardson
  • The front-end server must handle partial failure of backend services Product Info Service getProductInfo() getProductDetails() Front-end server getRecommendations() getReviews() How to provide a good user experience? X Recommendations Service Review Service @crichardson
  • Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions @crichardson
  • Futures are a great concurrency abstraction http://en.wikipedia.org/wiki/Futures_and_promises @crichardson
  • How futures work initiates Asynchronous operation Client get set Outcome Future @crichardson
  • Benefits Client does not know how the asynchronous operation is implemented Client can invoke multiple asynchronous operations and gets a Future for each one. @crichardson
  • REST client using Spring @Async trait ProductInfoService { def getProductInfo(productId: Long): java.util.concurrent.Future[ProductInfo] } @Component class ProductInfoServiceImpl extends ProducInfoService { val restTemplate : RestTemplate = ... Execute asynchronously in thread pool @Async def getProductInfo(productId: Long) = { new AsyncResult(restTemplate.getForObject(....)...) } } A Future containing a value @crichardson
  • ProductDetailsService @Component class ProductDetailsService @Autowired()(productInfoService: ProductInfoService, reviewService: ReviewService, recommendationService: RecommendationService) { def getProductDetails(productId: Long): ProductDetails = { val productInfoFuture = productInfoService.getProductInfo(productId) val recommendationsFuture = recommendationService.getRecommendations(productId) val reviewsFuture = reviewService.getReviews(productId) val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS) val recommendations = recommendationsFuture.get(10, TimeUnit.MILLISECONDS) val reviews = reviewsFuture.get(10, TimeUnit.MILLISECONDS) } ProductDetails(productInfo, recommendations, reviews) } @crichardson
  • ProductController @Controller class ProductController @Autowired()(productDetailsService : ProductDetailsService) { @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = productDetailsService.getProductDetails(productId) @crichardson
  • Not bad but... Blocks Tomcat thread until Future completes val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS) Not so scalable :-( @crichardson
  • ... and also... Java Futures work well for a single-level of asynchronous execution BUT #fail for more complex, scalable scenarios Difficult to compose and coordinate multiple concurrent operations http://techblog.netflix.com/2013/02/rxjava-netflix-api.html @crichardson
  • Better: Futures with callbacks no blocking! val f : Future[Int] = Future { ... } f onSuccess { case x : Int => println(x) } f onFailure { case e : Exception => println("exception thrown") } Guava ListenableFutures, Spring 4 ListenableFuture Java 8 CompletableFuture, Scala Futures @crichardson
  • Even better: Composable Futures val f1 = Future { val f2 = Future { ... ; 1 } ... ; 2 } Transforms Future val f4 = f2.map(_ * 2) assertEquals(4, Await.result(f4, 1 second)) val fzip = f1 zip f2 assertEquals((1, 2), Await.result(fzip, 1 second)) Combines two futures Scala, Java 8 CompletableFuture (partially) @crichardson
  • Scala futures are Monads def callB() : Future[...] = ... def callC() : Future[...] = ... def callD() : Future[...] = ... val result = for { (b, c) <- callB() zip callC(); d <- callD(b, c) } yield d Two calls execute in parallel And then invokes D result onSuccess { .... } Get the result of D @crichardson
  • Scala Future + RestTemplate import scala.concurrent.Future Scala Future @Component class ProductInfoService { def getProductInfo(productId: Long): Future[ProductInfo] = { Future { restTemplate.getForObject(....) } } } Executes in thread pool @crichardson
  • Scala Future + RestTemplate class ProductDetailsService @Autowired()(....) { def getProductDetails(productId: Long) = { val productInfoFuture = productInfoService.getProductInfo(productId) val recommendationsFuture = recommendationService.getRecommendations(productId) val reviewsFuture = reviewService.getReviews(productId) for (((productInfo, recommendations), reviews) <productInfoFuture zip recommendationsFuture zip reviewsFuture) yield ProductDetails(productInfo, recommendations, reviews) } } Non-blocking! @crichardson
  • Async Spring MVC + Scala Futures @Controller class ProductController ... { @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = { val productDetails = productDetailsService.getProductDetails(productId) val result = new DeferredResult[ProductDetails] productDetails onSuccess { case r => result.setResult(r) } productDetails onFailure { case t => result.setErrorResult(t) } result } Convert Scala Future to Spring MVC DeferredResult @crichardson
  • Servlet layer is asynchronous but the backend uses thread pools Need event-driven REST client @crichardson
  • About the Reactor pattern Defined by Doug Schmidt in 1995 Pattern for writing scalable servers Alternative to thread-per-connection model Single threaded event loop dispatches events on handles (e.g. sockets, file descriptors) to event handlers @crichardson
  • Reactor pattern structure Initiation Dispatcher handle_events() register_handler(h) select(handlers) for each h in handlers h.handle_event(type) end loop handlers handle Event Handler handle_event(type) get_handle() notifies creates owns uses Synchronous Event Demultiplexer Application select() @crichardson
  • Java NIO Selectors = Reactor pattern But that’s super low-level :-( @crichardson
  • Spring AsyncRestTemplate New in Spring 4 Mirrors RestTemplate Methods return a ListenableFuture = JDK 7 Future + callback methods Can use HttpComponents NIO-based AsyncHttpClient @crichardson
  • Using the AsyncRestTemplate val asyncRestTemplate = new AsyncRestTemplate( new HttpComponentsAsyncClientHttpRequestFactory()) override def getProductInfo(productId: Long) = { val listenableFuture = asyncRestTemplate.getForEntity("{baseUrl}/productinfo/{productId}", classOf[ProductInfo], baseUrl, productId) toScalaFuture(listenableFuture).map { _.getBody } } Convert to Scala Future and get entity http://hc.apache.org/httpcomponents-asyncclient-dev/ @crichardson
  • Converting ListenableFuture to Scala Future implicit def toScalaFuture[T](f : ListenableFuture[T]) : Future[T] = { val p = promise[T] The producer side of Scala Futures f.addCallback(new ListenableFutureCallback[T] { def onSuccess(result: T) { p.success(result)} def onFailure(t: Throwable) { p.failure(t) } }) p.future } Supply outcome Return future @crichardson
  • Now everything is non-blocking :-) @crichardson
  • If recommendation service is down... Never responds front-end server waits indefinitely Consumes valuable front-end server resources Page never displayed and customer gives up Returns an error Error returned to the front-end server error page is displayed Customer gives up @crichardson
  • Fault tolerance at Netflix Network timeouts and retries Invoke remote services via a bounded thread pool Use the Circuit Breaker pattern On failure: return default/cached data return error to caller Implementation: https://github.com/Netflix/Hystrix http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html @crichardson
  • Using Hystrix @Component class ProductInfoServiceImpl extends ProductInfoService { val restTemplate = RestTemplateFactory.makeRestTemplate() val baseUrl = ... Runs in thread pool class GetProductInfoCommand(productId: Long)extends HystrixCommand[ProductInfo](....) { override def run() = restTemplate. getForEntity("{baseUrl}/productinfo/{productId}", classOf[ProductInfo], baseUrl, productId).getBody } def getProductInfoUsingHystrix(productId: Long) : Future[ProductInfo] = { new GetProductInfoCommand(productId).queue() } Returns JDK Future } @crichardson
  • But how to accomplish this with eventdriven code @crichardson
  • How to handling partial failures? Fails if any Future has failed productDetailsFuture zip recommendationsFuture zip reviewsFuture @crichardson
  • Handling partial failures val recommendationsFuture = recommendationService. getRecommendations(userId,productId). recover { case _ => Recommendations(List()) } “catch-like” Maps Throwable to value @crichardson
  • Implementing a Timeout No timeout - callbacks might never be invoked :-( resultFuture onSuccess { case r => result.setResult(r) } resultFuture onFailure { case t => result.setErrorResult(t) } Await.result(resultFuture, timeout) Blocks until timeout:-( @crichardson
  • Non-blocking Timeout val future = ... val timedoutFuture = TimeoutFuture(future)(executionContext, 200.milleseconds) object TimeoutFuture { def apply[T](future: Future[T], onTimeout: => Unit = Unit) (implicit ec: ExecutionContext, after: Duration): Future[T] = { val timer = new HashedWheelTimer(10, TimeUnit.MILLISECONDS) val promise = Promise[T]() val timeout = timer.newTimeout(new TimerTask { def run(timeout: Timeout){ onTimeout promise.failure(new TimeoutException(s"Future timed out after ${after.toMillis}ms")) } }, after.toNanos, TimeUnit.NANOSECONDS) Future.firstCompletedOf(Seq(future, promise.future)). tap(_.onComplete { case result => timeout.cancel() }) } } Timer fails promise Outcome of first completed http://eng.42go.com/future-safefuture-timeout-cancelable/ @crichardson
  • Using the Akka Circuit Breaker import akka.pattern.CircuitBreaker val breaker = new CircuitBreaker(actorSystem.scheduler, maxFailures = 1, callTimeout = 100.milliseconds, resetTimeout = 1.minute) val resultFuture = breaker. withCircuitBreaker{ asynchronousOperationReturningFuture() } @crichardson
  • Limiting # of simultaneous requests val limiter = new ConcurrencyLimiter(maxConcurrentRequests=10, maxQueueSize=30) val resultFuture = limiter.withLimit { asynchronousOperationReturningFuture() } class ConcurrencyLimiter ... val concurrencyManager : ActorRef = ... def withLimit[T](body : => Future[T])(...) = (concurrencyManager ? ConcurrentExecutionManager.Request { () => body }).mapTo[T] @crichardson
  • Putting it all together @Component class ProductInfoServiceImpl @Autowired()(...) extends ProductService { val limiter = new ConcurrencyLimiter(...) val breaker = new CircuitBreaker(...) override def getProductInfo(productId: Long) = { ... breaker.withCircuitBreaker { limiter.withLimit { TimeoutFuture { ... AsyncRestTemplate.get ... } } } } @crichardson
  • Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions @crichardson
  • @crichardson
  • Why solve this problem for JavaScript? Browser invokes web services Implement front-end server/API gateway using NodeJS! @crichardson
  • What’s NodeJS? Designed for DIRTy apps @crichardson
  • JavaScript NodeJS Modules Reactor pattern @crichardson
  • Asynchronous JavaScript code = callback hell Scenarios: Sequential: A B C Fork and join: A and B C Code quickly becomes very messy @crichardson
  • Callback-based HTTP client request = require("request") handler = (error, clientResponse, body) -> if clientResponse.statusCode != 200 // ERROR else // SUCCESS request("http://.../productdetails/" + productId, handler) @crichardson
  • Messy callback code getProductDetails = (req, res) -> productId = req.params.productId result = {productId: productId} Returns a callback function makeHandler = (key) -> (error, clientResponse, body) -> if clientResponse.statusCode != 200 res.status(clientResponse.statusCode) res.write(body) res.end() else result[key] = JSON.parse(body) if (result.productInfo and result.recommendations and result.reviews) res.json(result) Have all three requests completed? request("http://localhost:3000/productdetails/" + productId, makeHandler("productInfo")) request("http://localhost:3000/recommendations/" + productId, makeHandler('recommendations')) request("http://localhost:3000/reviews/" + productId, makeHandler('reviews')) app.get('/productinfo/:productId', getProductInfo) @crichardson
  • Simplifying code with Promises (a.k.a. Futures) Functions return a promise - no callback parameter A promise represents an eventual outcome Use a library of functions for transforming and composing promises Promises/A+ specification - http://promises-aplus.github.io/promises-spec @crichardson
  • Basic promise API called when promise1 is fulfilled returns a promise or value promise2 = promise1.then(fulfilledHandler, errorHandler, ...) resolved with outcome of callback called when promise1 is rejected returns a promise or value @crichardson
  • About when.js Rich API = Promises spec + use full extensions Creation: when.defer() when.reject()... Combinators: all, some, join, map, reduce Other: Calling non-promise code timeout .... https://github.com/cujojs/when
  • Simpler promise-based code rest = require("rest") @httpClient = rest.chain(mime).chain(errorCode); No ugly callbacks getProductInfo : (productId) -> @httpClient path: "http://.../productinfo/" + productId Returns a promise @crichardson
  • Simpler promise-based code class ProductDetailsService getProductDetails: (productId) -> makeProductDetails = (productInfo, recommendations, reviews) -> details = productId: productId Array[Promise] productDetails: productInfo.entity recommendations: recommendations.entity reviews: reviews.entity details responses = [@getProductInfo(productId), @getRecommendations(productId), @getReviews(productId)] all(responses).spread(makeProductDetails) Promise[Array] @crichardson
  • Simpler promise-based code: HTTP handler getProductDetails = (req, res) -> productId = req.params.productId succeed = (productDetails) -> res.json(productDetails) fail = (something) -> res.send(500, JSON.stringify(something.entity || something)) productDetailsService. getDetails(productId). then(succeed, fail) app.get('/productdetails/:productId', getProductDetails) @crichardson
  • Writing robust client code @crichardson
  • Implementing timeouts Creates a new promise Original promise must complete within 300 msec timeout = require("when/timeout") withTimeout = (promise) -> timeout(300, promise) getProductDetails = (productId) -> ... withTimeout(client(...)) @crichardson
  • Recovering from failures Invoked to return default value if getRecommendations() fails getRecommendations(productId).otherwise( -> {}) @crichardson
  • Limiting # of concurrent requests ConcurrencyLimiter = require("./concurrencylimiter").ConcurrencyLimiter limiter = new ConcurrencyLimiter(maxQueueSize = 100, maxConcurrency = 10) getProductDetails = (productId) -> ... limiter.withLimit( -> client(...)) Homegrown code @crichardson
  • Circuit breaker CircuitBreaker = require("./circuitbreaker").CircuitBreaker productCircuitBreaker = new CircuitBreaker() getProductDetails = (productId) -> ... productCircuitBreaker.withCircuitBreaker( -> client(...)) Homegrown code @crichardson
  • Putting it all together getProductInfo = (productId) -> limiter.withLimit -> productCircuitBreaker.withCircuitBreaker -> withTimeout client path: "http://..../productinfo/" + productd getProductDetails: (productId) -> ... responses = [@getProductInfo(productId), @getRecommendations(productId).otherwise(() -> {}), @getReviews(productId).otherwise(() -> {})] all(responses).spread(succeed) @crichardson
  • Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions @crichardson
  • Let’s imagine you have a stream of trades and you need to calculate the rolling average price of each stock @crichardson
  • Spring Integration + Complex event processing (CEP) engine is a good choice @crichardson
  • But where is the high-level abstraction that solves this problem? @crichardson
  • Future[List[T]] Not applicable to infinite streams @crichardson
  • Introducing Reactive Extensions (Rx) The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. Using Rx, developers represent asynchronous data streams with Observables , query asynchronous data streams using LINQ operators , and ..... https://rx.codeplex.com/ @crichardson
  • About RxJava Reactive Extensions (Rx) for the JVM Implemented in Java Adaptors for Scala, Groovy and Clojure https://github.com/Netflix/RxJava @crichardson
  • RxJava core concepts An asynchronous stream of items class Observable<T> { Subscription subscribe(Observer<T> observer) ... } Used to unsubscribe Notifies interface Observer<T> { void onNext(T args) void onCompleted() void onError(Throwable e) } @crichardson
  • Comparing Observable to... Observer pattern - similar but adds Observer.onComplete() Observer.onError() Iterator pattern - mirror image Push rather than pull Future - similar but Represents a stream of multiple values @crichardson
  • So what? @crichardson
  • Transforming Observables class Observable<T> { Observable<T> take(int n); Observable<T> skip(int n); <R> Observable<R> map(Func1<T,R> func) <R> Observable<R> flatMap(Func1<T,Observable<R>> func) Observable<T> filter(Func1<T,java.lang.Boolean> predicate) ... } Scala-collection style methods @crichardson
  • Transforming observables Stream of streams! class Observable<T> { <K> Observable<GroupedObservable<K,T>> groupBy(Func1<T,K> keySelector) ... } Similar to Scala groupBy except results are emitted as items arrive @crichardson
  • Combining observables class Observable<T> { static <R,T1,T2> Observable<R> zip(Observable<T0> o1, Observable<T1> o2, Func2<T1,T2,R> reduceFunction) ... } Stream of results from reduceFunction Invoked with pairs of items from o1 and o2 @crichardson
  • Creating observables from data class Observable<T> { static Observable<T> from(Iterable<T> iterable]); static Observable<T> from(T items ...]); static Observable<T> from(Future<T> future]); ... } @crichardson
  • Creating observables from event sources Observable<T> o = Observable.create( new SubscriberFunc<T> () { Subscription onSubscribe(Observer<T> obs) { ... connect to event source.... Called once for each Observer Arranges to call obs.onNext/onComplete/... return new Subscriber () { void unsubscribe() { ... }; }; }); Called when unsubscribing @crichardson
  • Using Rx Observables instead of Futures @crichardson
  • Rx-based ProductInfoService @Component class ProductInfoService override def getProductInfo(productId: Long) = { val baseUrl = ... val responseEntity = asyncRestTemplate.getForEntity(baseUrl + "/productinfo/{productId}", classOf[ProductInfo], productId) toRxObservable(responseEntity).map { (r : ResponseEntity[ProductInfo]) => r.getBody } } @crichardson
  • ListenableFuture Observable implicit def toRxObservable[T](future: ListenableFuture[T]) : Observable[T] = { def create(o: Observer[T]) = { future.addCallback(new ListenableFutureCallback[T] { def onSuccess(result: T) { o.onNext(result) o.onCompleted() } def onFailure(t: Throwable) { o.onError(t) } }) new Subscription { def unsubscribe() {} } } Supply single value Indicate failure Do nothing Observable.create(create _) } @crichardson
  • Rx - ProductDetailsService @Component class ProductDetailsService @Autowired() (productInfoService: ProductInfoService, reviewService: ReviewService, ecommendationService: RecommendationService) { def getProductDetails(productId: Long) = { val productInfo = productInfoService.getProductInfo(productId) val recommendations = recommendationService.getRecommendations(productId) val reviews = reviewService.getReviews(productId) Just like Scala Futures Observable.zip(productInfo, recommendations, reviews, (p : ProductInfo, r : Recommendations, rv : Reviews) => ProductDetails(p, r, rv)) } } @crichardson
  • Rx - ProductController @Controller class ProductController @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = toDeferredResult(productDetailsService.getProductDetails(productId)) @crichardson
  • Rx - Observable DeferredResult implicit def toDeferredResult[T](observable : Observable[T]) = { val result = new DeferredResult[T] observable.subscribe(new Observer[T] { def onCompleted() {} def onError(e: Throwable) { result.setErrorResult(e) } def onNext(r: T) { result.setResult(r.asInstanceOf[T]) } }) result } @crichardson
  • RxObservables vs. Futures Much better than JDK 7 futures Comparable to Scala Futures Rx Scala code is slightly more verbose @crichardson
  • Making this code robust Hystrix works with Observables (and thread pools) But For event-driven code we are on our own @crichardson
  • Back to the stream of Trades averaging example... @crichardson
  • AMQP messages Observables 1 <amqp:inbound-channel-adapter ... /> <int:channel id="inboundEventsChannel"/> <int:service-activator input-channel="inboundEventsChannel" ref="amqpToObservableAdapter" method="handleMessage"/> @crichardson
  • AMQP messages Observables 2 class AmqpToObservableAdapter (actorRef : observerManager) { def createObservable() = Observable.create((o: Observer[_ >: String]) observerManager ! Subscribe(o) new Subscription { override def unsubscribe() { observerManager ! Unsubscribe(o) } } => { Manages and notifies observers }) def handleMessage(message : String) { observerManager ! Message(message) } } @crichardson
  • Calculating averages Observable<AveragePrice> calculateAverages(Observable<Trade> trades) { ... } class Trade { private String symbol; private double price; class AveragePrice { private String symbol; private double averagePrice; @crichardson
  • Using groupBy() Observable<Trade> APPL : 401 IBM : 405 CAT : 405 APPL: 403 groupBy( (trade) => trade.symbol) APPL : 401 APPL: 403 IBM : 405 CAT : 405 Observable<GroupedObservable<String, Trade>> ... @crichardson
  • Using window() Observable<Trade> APPL : 401 APPL : 405 APPL : 405 ... window(...) M secs APPL : 401 APPL : 405 APPL : 405 APPL : 405 APPL : 403 N secs N secs APPL : 405 APPL : 405 ... Observable<Observable<Trade>> @crichardson
  • Using reduce() Observable<Trade> APPL : 402 APPL : 405 APPL : 405 reduce(sumCalc) / length APPL : 404 Observable<AveragePrice> Singleton @crichardson
  • Using merge() Observable<Observable<AveragePrice>> APPL : 401 APPL: 403 IBM : 405 CAT : 405 ... CAT : 405 APPL: 403 merge() APPL : 401 Observable<AveragePrice> IBM : 405 @crichardson
  • RxJS / NodeJS example var rx = require("rx"); function tailFile (fileName) { var self = this; var o = rx.Observable.create(function (observer) { var watcher = self.tail(fileName, function (line) { observer.onNext(line); }); return function () { watcher.close(); } }); return o.map(parseLogLine); } function parseLogLine(line) { ... } @crichardson
  • Rx in the browser - implementing completion Change events TextChanges(input) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliSeconds(10)) .Select(word=>Completions(word)) .Switch() .Subscribe(ObserveChanges(output)); Observable Ajax call returning Observable Display completions Your Mouse is a Database http://queue.acm.org/detail.cfm?id=2169076 @crichardson
  • Summary Consuming web services asynchronously is essential Scala-style composable Futures are a powerful concurrency abstraction Rx Observables are even more powerful Rx Observables are a unifying abstraction for a wide variety of use cases @crichardson
  • @crichardson chris@chrisrichardson.net Questions? http://plainoldobjects.com @crichardson