• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)
 

Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)

on

  • 2,188 views

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 ...

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,188
Views on SlideShare
1,890
Embed Views
298

Actions

Likes
7
Downloads
50
Comments
0

2 Embeds 298

http://plainoldobjects.com 291
https://twitter.com 7

Accessibility

Categories

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 (#springone #s2gx) Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx) Presentation Transcript

    • @crichardson 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 Shipping Recomendations Product Info Reviews
    • @crichardson Reviews Product Info Sales ranking
    • @crichardson Related books Viewing history Forum
    • @crichardson + mobile apps
    • @crichardson Application architecture Product Info Service Desktop browser Native mobile client REST REST REST Recomendation Service Review Service Front end server API gatewayREST Mobile browser Web Application HTML
    • @crichardson Handling getProductDetails() Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails()
    • @crichardson Handling getProductDetails() - sequentially Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() Higher response time :-(
    • @crichardson Handling getProductDetails() - in parallel Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() Lower response time :-)
    • @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 Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() X How to provide a good user experience?
    • @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 Outcome Future Client get Asynchronous operation set initiates
    • @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 @Component class ProductInfoServiceImpl extends ProducInfoService { val restTemplate : RestTemplate = ... @Async def getProductInfo(productId: Long) = { new AsyncResult(restTemplate.getForObject(....)...) } } Execute asynchronously in thread pool A Future containing a value trait ProductInfoService { def getProductInfo(productId: Long): java.util.concurrent.Future[ProductInfo] }
    • @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... val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS) Blocks Tomcat thread until Future completes 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 { ... ; 1 } val f2 = Future { ... ; 2 } 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)) Transforms Future 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 result onSuccess { .... } Two calls execute in parallel And then invokes D Get the result of D
    • @crichardson Scala Future + RestTemplate import scala.concurrent.Future @Component class ProductInfoService { def getProductInfo(productId: Long): Future[ProductInfo] = { Future { restTemplate.getForObject(....) } } } Executes in thread pool Scala Future
    • @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 Event Handler handle_event(type) get_handle() Initiation Dispatcher handle_events() register_handler(h) select(handlers) for each h in handlers h.handle_event(type) end loop handle Synchronous Event Demultiplexer select() owns notifies uses handlers Application creates
    • @crichardson Java NIO Selectors = Reactor pattern But that’s super low-level :-(
    • @crichardson New in Spring 4 Mirrors RestTemplate Methods return a ListenableFuture = JDK 7 Future + callback methods Can use HttpComponents NIO-based AsyncHttpClient Spring AsyncRestTemplate
    • @crichardson Using the AsyncRestTemplate http://hc.apache.org/httpcomponents-asyncclient-dev/ 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
    • @crichardson Converting ListenableFuture to Scala Future implicit def toScalaFuture[T](f : ListenableFuture[T]) : Future[T] = { val p = promise[T] f.addCallback(new ListenableFutureCallback[T] { def onSuccess(result: T) { p.success(result)} def onFailure(t: Throwable) { p.failure(t) } }) p.future } The producer side of Scala Futures 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 = ... 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() } } Runs in thread pool Returns JDK Future
    • @crichardson But how to accomplish this with event- driven code
    • @crichardson How to handling partial failures? productDetailsFuture zip recommendationsFuture zip reviewsFuture Fails if any Future has failed
    • @crichardson Handling partial failures val recommendationsFuture = recommendationService. getRecommendations(userId,productId). recover { case _ => Recommendations(List()) } “catch-like” Maps Throwable to value
    • @crichardson Implementing a Timeout resultFuture onSuccess { case r => result.setResult(r) } resultFuture onFailure { case t => result.setErrorResult(t) } No timeout - callbacks might never be invoked :-( Await.result(resultFuture, timeout) Blocks until timeout:-(
    • @crichardson Non-blocking Timeout http://eng.42go.com/future-safefuture-timeout-cancelable/ 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() }) } } val future = ... val timedoutFuture = TimeoutFuture(future)(executionContext, 200.milleseconds) Timer fails promise Outcome of first completed
    • @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 NodeJS JavaScript Reactor pattern Modules
    • @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} 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) 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) Returns a callback function Have all three requests completed?
    • @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 promise2 = promise1.then(fulfilledHandler, errorHandler, ...) called when promise1 is fulfilled returns a promise or value resolved with outcome of callback called when promise1 is rejected returns a promise or value
    • 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
    • @crichardson Simpler promise-based code rest = require("rest") @httpClient = rest.chain(mime).chain(errorCode); getProductInfo : (productId) -> @httpClient path: "http://.../productinfo/" + productId Returns a promise No ugly callbacks
    • @crichardson Simpler promise-based code class ProductDetailsService getProductDetails: (productId) -> makeProductDetails = (productInfo, recommendations, reviews) -> details = productId: productId productDetails: productInfo.entity recommendations: recommendations.entity reviews: reviews.entity details responses = [@getProductInfo(productId), @getRecommendations(productId), @getReviews(productId)] all(responses).spread(makeProductDetails) Array[Promise] 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 timeout = require("when/timeout") withTimeout = (promise) -> timeout(300, promise) getProductDetails = (productId) -> ... withTimeout(client(...)) Creates a new promise Original promise must complete within 300 msec
    • @crichardson Recovering from failures getRecommendations(productId).otherwise( -> {}) Invoked to return default value if getRecommendations() fails
    • @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 getProductDetails: (productId) -> ... responses = [@getProductInfo(productId), @getRecommendations(productId).otherwise(() -> {}), @getReviews(productId).otherwise(() -> {})] all(responses).spread(succeed) getProductInfo = (productId) -> limiter.withLimit -> productCircuitBreaker.withCircuitBreaker -> withTimeout client path: "http://..../productinfo/" + productd
    • @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 class Observable<T> { Subscription subscribe(Observer<T> observer) ... } interface Observer<T> { void onNext(T args) void onCompleted() void onError(Throwable e) } Notifies An asynchronous stream of items Used to unsubscribe
    • @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 class Observable<T> { <K> Observable<GroupedObservable<K,T>> groupBy(Func1<T,K> keySelector) ... } Similar to Scala groupBy except results are emitted as items arrive Stream of streams!
    • @crichardson Combining observables class Observable<T> { static <R,T1,T2> Observable<R> zip(Observable<T0> o1, Observable<T1> o2, Func2<T1,T2,R> reduceFunction) ... } Invoked with pairs of items from o1 and o2 Stream of results from reduceFunction
    • @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.... return new Subscriber () { void unsubscribe() { ... }; }; }); Called once for each Observer Called when unsubscribing Arranges to call obs.onNext/onComplete/...
    • @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() {} } } Observable.create(create _) } Supply single value Indicate failure Do nothing
    • @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) Observable.zip(productInfo, recommendations, reviews, (p : ProductInfo, r : Recommendations, rv : Reviews) => ProductDetails(p, r, rv)) } } Just like Scala Futures
    • @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) } } }) def handleMessage(message : String) { observerManager ! Message(message) } } Manages and notifies observers
    • @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() APPL : 401 IBM : 405 CAT : 405 APPL: 403 groupBy( (trade) => trade.symbol) APPL : 401 IBM : 405 CAT : 405 ... APPL: 403 Observable<GroupedObservable<String, Trade>> Observable<Trade>
    • @crichardson Using window() APPL : 401 APPL : 405 APPL : 405 ... APPL : 401 APPL : 405 APPL : 405 APPL : 405 APPL : 405 APPL : 403 APPL : 405 ... window(...) Observable<Trade> Observable<Observable<Trade>> N secs N secs M secs
    • @crichardson Using reduce() APPL : 402 APPL : 405 APPL : 405 APPL : 404 reduce(sumCalc) / length Observable<Trade> Observable<AveragePrice> Singleton
    • @crichardson Using merge() merge() APPL : 401 IBM : 405 CAT : 405 ... APPL: 403 APPL : 401 IBM : 405 CAT : 405 APPL: 403 Observable<Observable<AveragePrice>> Observable<AveragePrice>
    • @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 TextChanges(input) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliSeconds(10)) .Select(word=>Completions(word)) .Switch() .Subscribe(ObserveChanges(output)); Your Mouse is a Database http://queue.acm.org/detail.cfm?id=2169076 Ajax call returning Observable Change events Observable Display completions
    • @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 Questions? @crichardson chris@chrisrichardson.net http://plainoldobjects.com