futures and rx observables: powerful abstractions for consuming web services asynchronously...
DESCRIPTION
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
![Page 1: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/3.jpg)
@crichardson
About Chris
![Page 4: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/4.jpg)
@crichardson
(About Chris)
![Page 5: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/5.jpg)
@crichardson
About Chris()
![Page 6: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/6.jpg)
@crichardson
About Chris
![Page 7: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/8.jpg)
@crichardson
About Chris
![Page 9: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/11.jpg)
@crichardson
Shipping
Recomendations
ProductInfo
Reviews
![Page 12: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/12.jpg)
@crichardson
Reviews
ProductInfo
Sales ranking
![Page 13: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/13.jpg)
@crichardson
Related books
Viewing history
Forum
![Page 14: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/14.jpg)
@crichardson
+ mobile apps
![Page 15: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/43.jpg)
@crichardson
Now everything is non-blocking :-)
![Page 44: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/56.jpg)
@crichardson
![Page 57: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/59.jpg)
@crichardson
NodeJS
JavaScript
Reactor pattern
Modules
![Page 60: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/69.jpg)
@crichardson
Writing robust client code
![Page 70: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/84.jpg)
@crichardson
So what?
![Page 85: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/html5/thumbnails/90.jpg)
@crichardson
Using Rx Observables instead of Futures
![Page 91: Futures and Rx Observables: powerful abstractions for consuming web services asynchronously (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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 (#springone #s2gx)](https://reader033.vdocuments.mx/reader033/viewer/2022060108/554f46cbb4c905423f8b49ab/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