Futures and Rx Observables: powerful abstractions for consuming web services asynchronously
-
Upload
spring-io -
Category
Technology
-
view
4.692 -
download
5
description
Transcript of Futures and Rx Observables: powerful abstractions for consuming web services asynchronously
![Page 1: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/1.jpg)
@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
![Page 2: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/2.jpg)
@crichardson
Presentation goal
Learn how to use (Scala) Futures and Rx Observables to write
simple yet robust and scalable concurrent code
![Page 3: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/3.jpg)
@crichardson
About Chris
![Page 4: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/4.jpg)
@crichardson
(About Chris)
![Page 5: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/5.jpg)
@crichardson
About Chris()
![Page 6: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/6.jpg)
@crichardson
About Chris
![Page 7: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/7.jpg)
@crichardson
About Chris
http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
![Page 8: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/8.jpg)
@crichardson
About Chris
![Page 9: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/9.jpg)
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
![Page 10: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/10.jpg)
@crichardson
Let’s imagine you are building an online store
![Page 11: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/11.jpg)
@crichardson
Shipping
Recomendations
ProductInfo
Reviews
![Page 12: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/12.jpg)
@crichardson
Reviews
ProductInfo
Sales ranking
![Page 13: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/13.jpg)
@crichardson
Related books
Viewing history
Forum
![Page 14: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/14.jpg)
@crichardson
+ mobile apps
![Page 15: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/15.jpg)
@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
![Page 16: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/16.jpg)
@crichardson
Handling getProductDetails()
Front-end server
Product Info Service
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
![Page 17: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/17.jpg)
@crichardson
Handling getProductDetails() - sequentially
Front-end server
Product Info Service
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
Higher response time :-(
![Page 18: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/18.jpg)
@crichardson
Handling getProductDetails() - in parallel
Front-end server
Product Info Service
RecommendationsService
ReviewService
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
Lower response time :-)
![Page 19: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/19.jpg)
@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
![Page 20: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/20.jpg)
@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?
![Page 21: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/21.jpg)
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
![Page 22: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/22.jpg)
@crichardson
Futures are a great concurrency abstraction
http://en.wikipedia.org/wiki/Futures_and_promises
![Page 23: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/23.jpg)
@crichardson
How futures work
Outcome
Future
Client
get
Asynchronous operation
set
initiates
![Page 24: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/24.jpg)
@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.
![Page 25: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/25.jpg)
@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]}
![Page 26: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/26.jpg)
@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)
![Page 27: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/27.jpg)
@crichardson
ProductController
@Controllerclass ProductController @Autowired()(productDetailsService : ProductDetailsService) {
@RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) =
productDetailsService.getProductDetails(productId)
![Page 28: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/28.jpg)
@crichardson
Not bad but...
val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS)
Blocks Tomcat thread until Future completes
Not so scalable :-(
![Page 29: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/29.jpg)
@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
![Page 30: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/30.jpg)
@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
![Page 31: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/31.jpg)
@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)
![Page 32: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/32.jpg)
@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
![Page 33: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/33.jpg)
@crichardson
Scala Future + RestTemplateimport scala.concurrent.Future
@Componentclass ProductInfoService {
def getProductInfo(productId: Long): Future[ProductInfo] = { Future { restTemplate.getForObject(....) } }
}
Executes in thread pool
Scala Future
![Page 34: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/34.jpg)
@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!
![Page 35: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/35.jpg)
@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
![Page 36: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/36.jpg)
@crichardson
Servlet layer is asynchronous but the backend uses thread pools
⇒Need event-driven REST client
![Page 37: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/37.jpg)
@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
![Page 38: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/38.jpg)
@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
![Page 39: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/39.jpg)
@crichardson
Java NIO Selectors = Reactor pattern
But that’s super low-level :-(
![Page 40: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/40.jpg)
@crichardson
New in Spring 4
Mirrors RestTemplate
Methods return a ListenableFuture = JDK 7 Future + callback methods
Can use HttpComponents NIO-based AsyncHttpClient
Spring AsyncRestTemplate
![Page 41: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/41.jpg)
@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
![Page 42: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/42.jpg)
@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
![Page 43: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/43.jpg)
@crichardson
Now everything is non-blocking :-)
![Page 44: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/44.jpg)
@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
![Page 45: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/45.jpg)
@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
![Page 46: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/46.jpg)
@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
![Page 47: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/47.jpg)
@crichardson
But how to accomplish this with event-driven code
![Page 48: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/48.jpg)
@crichardson
How to handling partial failures?
productDetailsFuture zip recommendationsFuture zip reviewsFuture
Fails if any Future has failed
![Page 49: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/49.jpg)
@crichardson
Handling partial failuresval recommendationsFuture = recommendationService. getRecommendations(userId,productId). recover { case _ => Recommendations(List()) }
“catch-like” Maps Throwable to value
![Page 50: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/50.jpg)
@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:-(
![Page 51: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/51.jpg)
@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
![Page 52: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/52.jpg)
@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() }
![Page 53: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/53.jpg)
@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]
![Page 54: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/54.jpg)
@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 ... } } } }
![Page 55: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/55.jpg)
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
![Page 56: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/56.jpg)
@crichardson
![Page 57: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/57.jpg)
@crichardson
Why solve this problem for JavaScript?
Browser invokes web services
Implement front-end server/API gateway using NodeJS!
![Page 58: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/58.jpg)
@crichardson
What’s NodeJS?
Designed for DIRTy apps
![Page 59: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/59.jpg)
@crichardson
NodeJS
JavaScript
Reactor pattern
Modules
![Page 60: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/60.jpg)
@crichardson
Asynchronous JavaScript code = callback hell
Scenarios:
Sequential: A ⇒ B ⇒ C
Fork and join: A and B ⇒ C
Code quickly becomes very messy
![Page 61: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/61.jpg)
@crichardson
Callback-based HTTP client
request = require("request") handler = (error, clientResponse, body) -> if clientResponse.statusCode != 200 // ERROR else // SUCCESS
request("http://.../productdetails/" + productId, handler)
![Page 62: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/62.jpg)
@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?
![Page 63: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/63.jpg)
@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
![Page 64: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/64.jpg)
@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
![Page 65: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/65.jpg)
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
![Page 66: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/66.jpg)
@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
![Page 67: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/67.jpg)
@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]
![Page 68: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/68.jpg)
@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)
![Page 69: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/69.jpg)
@crichardson
Writing robust client code
![Page 70: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/70.jpg)
@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
![Page 71: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/71.jpg)
@crichardson
Recovering from failures
getRecommendations(productId).otherwise( -> {})
Invoked to return default value if getRecommendations() fails
![Page 72: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/72.jpg)
@crichardson
Limiting # of concurrent requests
ConcurrencyLimiter = require("./concurrencylimiter").ConcurrencyLimiter
limiter = new ConcurrencyLimiter(maxQueueSize = 100, maxConcurrency = 10)
getProductDetails = (productId) -> ... limiter.withLimit( -> client(...))
Homegrown code
![Page 73: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/73.jpg)
@crichardson
Circuit breaker
CircuitBreaker = require("./circuitbreaker").CircuitBreaker
productCircuitBreaker = new CircuitBreaker()
getProductDetails = (productId) -> ... productCircuitBreaker.withCircuitBreaker( -> client(...))
Homegrown code
![Page 74: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/74.jpg)
@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
![Page 75: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/75.jpg)
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
![Page 76: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/76.jpg)
@crichardson
Let’s imagine you have a stream of tradesand
you need to calculate the rolling average price of each stock
![Page 77: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/77.jpg)
@crichardson
Spring Integration + Complex event processing (CEP) engine is a good
choice
![Page 78: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/78.jpg)
@crichardson
But where is the high-level abstraction that solves this problem?
![Page 79: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/79.jpg)
@crichardson
Future[List[T]]
Not applicable to infinite streams
![Page 80: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/80.jpg)
@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/
![Page 81: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/81.jpg)
@crichardson
About RxJava
Reactive Extensions (Rx) for the JVM
Implemented in Java
Adaptors for Scala, Groovy and Clojure
https://github.com/Netflix/RxJava
![Page 82: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/82.jpg)
@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
![Page 83: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/83.jpg)
@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
![Page 84: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/84.jpg)
@crichardson
So what?
![Page 85: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/85.jpg)
@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
![Page 86: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/86.jpg)
@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!
![Page 87: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/87.jpg)
@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
![Page 88: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/88.jpg)
@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]); ...}
![Page 89: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/89.jpg)
@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/...
![Page 90: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/90.jpg)
@crichardson
Using Rx Observables instead of Futures
![Page 91: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/91.jpg)
@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 }
}
![Page 92: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/92.jpg)
@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
![Page 93: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/93.jpg)
@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
![Page 94: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/94.jpg)
@crichardson
Rx - ProductController
@Controllerclass ProductController
@RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = toDeferredResult(productDetailsService.getProductDetails(productId))
![Page 95: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/95.jpg)
@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 }
![Page 96: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/96.jpg)
@crichardson
RxObservables vs. Futures
Much better than JDK 7 futures
Comparable to Scala Futures
Rx Scala code is slightly more verbose
![Page 97: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/97.jpg)
@crichardson
Making this code robust
Hystrix works with Observables (and thread pools)
But
For event-driven code we are on our own
![Page 98: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/98.jpg)
@crichardson
Back to the stream of Trades averaging example...
![Page 99: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/99.jpg)
@crichardson
AMQP messages ⇒ Observables 1
<amqp:inbound-channel-adapter ... />
<int:channel id="inboundEventsChannel"/> <int:service-activator input-channel="inboundEventsChannel" ref="amqpToObservableAdapter" method="handleMessage"/>
![Page 100: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/100.jpg)
@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
![Page 101: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/101.jpg)
@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;
![Page 102: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/102.jpg)
@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>
![Page 103: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/103.jpg)
@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
![Page 104: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/104.jpg)
@crichardson
Using reduce()
APPL : 402 APPL : 405 APPL : 405
APPL : 404
reduce(sumCalc) / length
Observable<Trade>
Observable<AveragePrice> Singleton
![Page 105: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/105.jpg)
@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>
![Page 106: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/106.jpg)
@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) { ... }
![Page 107: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/107.jpg)
@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
![Page 108: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously](https://reader034.fdocuments.in/reader034/viewer/2022052619/554fb094b4c905ad218b5207/html5/thumbnails/108.jpg)
@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