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

@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)

@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)

@crichardson

About Chris

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

@crichardson

(About Chris)

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

@crichardson

About Chris()

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

@crichardson

About Chris

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

@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)

@crichardson

About Chris

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

@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)

@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)

@crichardson

Shipping

Recomendations

ProductInfo

Reviews

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

@crichardson

Reviews

ProductInfo

Sales ranking

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

@crichardson

Related books

Viewing history

Forum

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

@crichardson

+ mobile apps

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

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@crichardson

Now everything is non-blocking :-)

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

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@crichardson

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

@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)

@crichardson

What’s NodeJS?

Designed for DIRTy apps

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

@crichardson

NodeJS

JavaScript

Reactor pattern

Modules

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

@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)

@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)

@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)

@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)

@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)

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)

@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)

@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)

@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)

@crichardson

Writing robust client code

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

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@crichardson

Future[List[T]]

Not applicable to infinite streams

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

@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)

@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)

@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)

@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)

@crichardson

So what?

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

@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)

@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)

@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)

@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)

@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)

@crichardson

Using Rx Observables instead of Futures

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

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@crichardson

Back to the stream of Trades averaging example...

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

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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)

@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

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

@crichardson

Questions?

@crichardson [email protected]

http://plainoldobjects.com


Top Related