futures and rx observables: powerful abstractions for consuming web services asynchronously
DESCRIPTION
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.TRANSCRIPT
@crichardson
Consuming web services asynchronously with Futures
and Rx ObservablesChris Richardson
Author of POJOs in ActionFounder of the original CloudFoundry.com
@[email protected]://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
ProductInfo
Reviews
@crichardson
Reviews
ProductInfo
Sales ranking
@crichardson
Related books
Viewing history
Forum
@crichardson
+ mobile apps
@crichardson
Application architecture
Product Info ServiceDesktop browser
Native mobile client
REST
REST
REST
Recomendation Service
Review Service
Front end server
API gatewayREST
Mobile browser
Web ApplicationHTML
@crichardson
Handling getProductDetails()
Front-end server
Product Info Service
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
@crichardson
Handling getProductDetails() - sequentially
Front-end server
Product Info Service
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
Higher response time :-(
@crichardson
Handling getProductDetails() - in parallel
Front-end server
Product Info Service
RecommendationsService
ReviewService
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
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails() XHow 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
@Componentclass 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@Componentclass 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
@Controllerclass 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 ListenableFutureJava 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 f2assertEquals((1, 2), Await.result(fzip, 1 second))
Transforms Future
Combines two futures
Scala, Java 8 CompletableFuture (partially)
@crichardson
Scala futures are Monadsdef 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 + RestTemplateimport scala.concurrent.Future
@Componentclass ProductInfoService {
def getProductInfo(productId: Long): Future[ProductInfo] = { Future { restTemplate.getForObject(....) } }
}
Executes in thread pool
Scala Future
@crichardson
Scala Future + RestTemplateclass 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@Controllerclass 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 Handlerhandle_event(type)get_handle()
Initiation Dispatcherhandle_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 outcomeReturn 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 NetflixNetwork 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@Componentclass 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 failuresval 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 requestsval 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@Componentclass 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 codegetProductDetails = (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 fulfilledreturns a promise or value
resolved with outcome of callbackcalled when promise1 is rejected
returns a promise or value
About when.jsRich 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 handlergetProductDetails = (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 promiseOriginal 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 tradesand
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@Componentclass 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@Componentclass 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
@Controllerclass 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 2class 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 examplevar 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 Databasehttp://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