SlideShare une entreprise Scribd logo
1  sur  109
Télécharger pour lire hors ligne
@crichardson
Consuming web services asynchronously
with Futures
and Rx Observables
Chris Richardson
Author of POJOs in Action
Founder of the original CloudFoundry.com
@crichardson
chris@chrisrichardson.net
http://plainoldobjects.com
@crichardson
Presentation goal
Learn how to use (Scala) Futures
and Rx Observables to write
simple yet robust and scalable
concurrent code
@crichardson
About Chris
@crichardson
(About Chris)
@crichardson
About Chris()
@crichardson
About Chris
@crichardson
About Chris
http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
@crichardson
About Chris
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
@crichardson
Let’s imagine you are building an online
store
@crichardson
Shipping
Recomendations
Product
Info
Reviews
@crichardson
Reviews
Product
Info
Sales
ranking
@crichardson
Related
books
Viewing
history
Forum
@crichardson
+ mobile apps
@crichardson
Application architecture
Product Info Service
Desktop
browser
Native mobile
client
REST
REST
REST
Recomendation Service
Review Service
Front end server
API gatewayREST
Mobile
browser
Web Application
HTML
@crichardson
Handling getProductDetails()
Front-end server
Product Info Service
Recommendations
Service
Review
Service
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
@crichardson
Handling getProductDetails() - sequentially
Front-end server
Product Info Service
Recommendations
Service
Review
Service
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
Higher response time :-(
@crichardson
Handling getProductDetails() - in parallel
Front-end server
Product Info Service
Recommendations
Service
Review
Service
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
Lower response time :-)
@crichardson
Implementing a concurrent REST client
Thread-pool based approach
executorService.submit(new Callable(...))
Simpler but less scalable - lots of idle threads consuming memory
Event-driven approach
NIO with completion callbacks
More complex but more scalable
@crichardson
The front-end server must handle partial
failure of backend services
Front-end server
Product Info Service
Recommendations
Service
Review
Service
getProductInfo()
getRecommendations()
getReviews()
getProductDetails()
X
How to provide a
good user
experience?
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
@crichardson
Futures are a great concurrency
abstraction
http://en.wikipedia.org/wiki/Futures_and_promises
@crichardson
How futures work
Outcome
Future
Client
get
Asynchronous
operation
set
initiates
@crichardson
Benefits
Client does not know how the asynchronous operation is implemented
Client can invoke multiple asynchronous operations and gets a Future for each
one.
@crichardson
REST client using Spring @Async
@Component
class ProductInfoServiceImpl extends ProducInfoService {
val restTemplate : RestTemplate = ...
@Async
def getProductInfo(productId: Long) = {
new AsyncResult(restTemplate.getForObject(....)...)
}
}
Execute asynchronously in thread pool
A Future
containing a value
trait ProductInfoService {
def getProductInfo(productId: Long): java.util.concurrent.Future[ProductInfo]
}
@crichardson
ProductDetailsService
@Component
class ProductDetailsService
@Autowired()(productInfoService: ProductInfoService,
reviewService: ReviewService,
recommendationService: RecommendationService) {
def getProductDetails(productId: Long): ProductDetails = {
val productInfoFuture = productInfoService.getProductInfo(productId)
}
}
val recommendationsFuture = recommendationService.getRecommendations(productId)
val reviewsFuture = reviewService.getReviews(productId)
val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS)
val recommendations =
recommendationsFuture.get(10, TimeUnit.MILLISECONDS)
val reviews = reviewsFuture.get(10, TimeUnit.MILLISECONDS)
ProductDetails(productInfo, recommendations, reviews)
@crichardson
ProductController
@Controller
class ProductController
@Autowired()(productDetailsService : ProductDetailsService) {
@RequestMapping(Array("/productdetails/{productId}"))
@ResponseBody
def productDetails(@PathVariable productId: Long) =
productDetailsService.getProductDetails(productId)
@crichardson
Not bad but...
val productInfo =
productInfoFuture.get(300, TimeUnit.MILLISECONDS)
Blocks Tomcat thread until Future
completes
Not so scalable :-(
@crichardson
... and also...
Java Futures work well for a single-level of asynchronous execution
BUT
#fail for more complex, scalable scenarios
Difficult to compose and coordinate multiple concurrent operations
http://techblog.netflix.com/2013/02/rxjava-netflix-api.html
@crichardson
Better: Futures with callbacks no blocking!
val f : Future[Int] = Future { ... }
f onSuccess {
case x : Int => println(x)
}
f onFailure {
case e : Exception => println("exception thrown")
}
Guava ListenableFutures, Spring 4 ListenableFuture
Java 8 CompletableFuture, Scala Futures
@crichardson
Even better: Composable Futures
val f1 = Future { ... ; 1 }
val f2 = Future { ... ; 2 }
val f4 = f2.map(_ * 2)
assertEquals(4, Await.result(f4, 1 second))
val fzip = f1 zip f2
assertEquals((1, 2), Await.result(fzip, 1 second))
Transforms Future
Combines two futures
Scala, Java 8 CompletableFuture (partially)
@crichardson
Scala futures are Monads
def callB() : Future[...] = ...
def callC() : Future[...] = ...
def callD() : Future[...] = ...
val result = for {
(b, c) <- callB() zip callC();
d <- callD(b, c)
} yield d
result onSuccess { .... }
Two calls execute in parallel
And then invokes D
Get the result of D
@crichardson
Scala Future + RestTemplate
import scala.concurrent.Future
@Component
class ProductInfoService {
def getProductInfo(productId: Long): Future[ProductInfo] = {
Future { restTemplate.getForObject(....) }
}
}
Executes in thread pool
Scala Future
@crichardson
Scala Future + RestTemplate
class ProductDetailsService @Autowired()(....) {
def getProductDetails(productId: Long) = {
val productInfoFuture = productInfoService.getProductInfo(productId)
val recommendationsFuture = recommendationService.getRecommendations(productId)
val reviewsFuture = reviewService.getReviews(productId)
for (((productInfo, recommendations), reviews) <-
productInfoFuture zip recommendationsFuture zip reviewsFuture)
yield ProductDetails(productInfo, recommendations, reviews)
}
}
Non-blocking!
@crichardson
Async Spring MVC + Scala Futures
@Controller
class ProductController ... {
@RequestMapping(Array("/productdetails/{productId}"))
@ResponseBody
def productDetails(@PathVariable productId: Long) = {
val productDetails =
productDetailsService.getProductDetails(productId)
val result = new DeferredResult[ProductDetails]
productDetails onSuccess {
case r => result.setResult(r)
}
productDetails onFailure {
case t => result.setErrorResult(t)
}
result
}
Convert Scala Future to
Spring MVC
DeferredResult
@crichardson
Servlet layer is asynchronous but the
backend uses thread pools
Need event-driven REST client
@crichardson
About the Reactor pattern
Defined by Doug Schmidt in 1995
Pattern for writing scalable servers
Alternative to thread-per-connection model
Single threaded event loop dispatches events on handles (e.g. sockets, file
descriptors) to event handlers
@crichardson
Reactor pattern structure
Event Handler
handle_event(type)
get_handle()
Initiation Dispatcher
handle_events()
register_handler(h)
select(handlers)
for each h in handlers
h.handle_event(type)
end loop
handle
Synchronous Event
Demultiplexer
select()
owns
notifies
uses
handlers
Application
creates
@crichardson
Java NIO Selectors = Reactor pattern
But that’s super low-level :-(
@crichardson
New in Spring 4
Mirrors RestTemplate
Methods return a ListenableFuture = JDK 7 Future + callback methods
Can use HttpComponents NIO-based AsyncHttpClient
Spring AsyncRestTemplate
@crichardson
Using the AsyncRestTemplate
http://hc.apache.org/httpcomponents-asyncclient-dev/
val asyncRestTemplate = new AsyncRestTemplate(
new HttpComponentsAsyncClientHttpRequestFactory())
override def getProductInfo(productId: Long) = {
val listenableFuture =
asyncRestTemplate.getForEntity("{baseUrl}/productinfo/{productId}",
classOf[ProductInfo],
baseUrl, productId)
toScalaFuture(listenableFuture).map { _.getBody }
}
Convert to Scala Future and get entity
@crichardson
Converting ListenableFuture to Scala Future
implicit def toScalaFuture[T](f : ListenableFuture[T]) : Future[T] = {
val p = promise[T]
f.addCallback(new ListenableFutureCallback[T] {
def onSuccess(result: T) { p.success(result)}
def onFailure(t: Throwable) { p.failure(t) }
})
p.future
}
The producer side of Scala Futures
Supply outcome
Return future
@crichardson
Now everything is non-blocking :-)
@crichardson
If recommendation service is down...
Never responds front-end server waits indefinitely
Consumes valuable front-end server resources
Page never displayed and customer gives up
Returns an error
Error returned to the front-end server error page is displayed
Customer gives up
@crichardson
Fault tolerance at Netflix
Network timeouts and retries
Invoke remote services via a bounded thread pool
Use the Circuit Breaker pattern
On failure:
return default/cached data
return error to caller
Implementation: https://github.com/Netflix/Hystrix
http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
@crichardson
Using Hystrix
@Component
class ProductInfoServiceImpl extends ProductInfoService {
val restTemplate = RestTemplateFactory.makeRestTemplate()
val baseUrl = ...
class GetProductInfoCommand(productId: Long)extends
HystrixCommand[ProductInfo](....) {
override def run() =
restTemplate.
getForEntity("{baseUrl}/productinfo/{productId}",
classOf[ProductInfo],
baseUrl, productId).getBody
}
def getProductInfoUsingHystrix(productId: Long) : Future[ProductInfo] = {
new GetProductInfoCommand(productId).queue()
}
}
Runs in thread pool
Returns JDK Future
@crichardson
But how to accomplish this with event-
driven code
@crichardson
How to handling partial failures?
productDetailsFuture zip
recommendationsFuture zip reviewsFuture
Fails if any Future has failed
@crichardson
Handling partial failures
val recommendationsFuture =
recommendationService.
getRecommendations(userId,productId).
recover {
case _ => Recommendations(List())
}
“catch-like” Maps Throwable to value
@crichardson
Implementing a Timeout
resultFuture onSuccess { case r => result.setResult(r) }
resultFuture onFailure { case t => result.setErrorResult(t) }
No timeout - callbacks might never be
invoked :-(
Await.result(resultFuture, timeout)
Blocks until timeout:-(
@crichardson
Non-blocking Timeout
http://eng.42go.com/future-safefuture-timeout-cancelable/
object TimeoutFuture {
def apply[T](future: Future[T], onTimeout: => Unit = Unit)
(implicit ec: ExecutionContext, after: Duration): Future[T] = {
val timer = new HashedWheelTimer(10, TimeUnit.MILLISECONDS)
val promise = Promise[T]()
val timeout = timer.newTimeout(new TimerTask {
def run(timeout: Timeout){
onTimeout
promise.failure(new TimeoutException(s"Future timed out after ${after.toMillis}ms"))
}
}, after.toNanos, TimeUnit.NANOSECONDS)
Future.firstCompletedOf(Seq(future, promise.future)).
tap(_.onComplete { case result => timeout.cancel() })
}
}
val future = ...
val timedoutFuture = TimeoutFuture(future)(executionContext, 200.milleseconds)
Timer fails
promise
Outcome of first
completed
@crichardson
Using the Akka Circuit Breaker
import akka.pattern.CircuitBreaker
val breaker =
new CircuitBreaker(actorSystem.scheduler,
maxFailures = 1,
callTimeout = 100.milliseconds,
resetTimeout = 1.minute)
val resultFuture = breaker.
withCircuitBreaker{ asynchronousOperationReturningFuture() }
@crichardson
Limiting # of simultaneous requests
val limiter =
new ConcurrencyLimiter(maxConcurrentRequests=10, maxQueueSize=30)
val resultFuture = limiter.withLimit {
asynchronousOperationReturningFuture()
}
class ConcurrencyLimiter ...
val concurrencyManager : ActorRef = ...
def withLimit[T](body : => Future[T])(...) =
(concurrencyManager ?
ConcurrentExecutionManager.Request { () => body }).mapTo[T]
@crichardson
Putting it all together
@Component
class ProductInfoServiceImpl @Autowired()(...) extends ProductService {
val limiter = new ConcurrencyLimiter(...)
val breaker = new CircuitBreaker(...)
override def getProductInfo(productId: Long) = {
...
breaker.withCircuitBreaker {
limiter.withLimit {
TimeoutFuture { ... AsyncRestTemplate.get ... }
}
}
}
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
@crichardson
@crichardson
Why solve this problem for JavaScript?
Browser invokes web services
Implement front-end server/API gateway using NodeJS!
@crichardson
What’s NodeJS?
Designed for DIRTy apps
@crichardson
NodeJS
JavaScript
Reactor
pattern
Modules
@crichardson
Asynchronous JavaScript code =
callback hell
Scenarios:
Sequential: A B C
Fork and join: A and B C
Code quickly becomes very messy
@crichardson
Callback-based HTTP client
request = require("request")
handler = (error, clientResponse, body) ->
if clientResponse.statusCode != 200
// ERROR
else
// SUCCESS
request("http://.../productdetails/" + productId, handler)
@crichardson
Messy callback code
getProductDetails = (req, res) ->
productId = req.params.productId
result = {productId: productId}
makeHandler = (key) ->
(error, clientResponse, body) ->
if clientResponse.statusCode != 200
res.status(clientResponse.statusCode)
res.write(body)
res.end()
else
result[key] = JSON.parse(body)
if (result.productInfo and result.recommendations and result.reviews)
res.json(result)
request("http://localhost:3000/productdetails/" + productId, makeHandler("productInfo"))
request("http://localhost:3000/recommendations/" + productId, makeHandler('recommendations'))
request("http://localhost:3000/reviews/" + productId, makeHandler('reviews'))
app.get('/productinfo/:productId', getProductInfo)
Returns a callback
function
Have all three requests
completed?
@crichardson
Simplifying code with Promises (a.k.a.
Futures)
Functions return a promise - no callback parameter
A promise represents an eventual outcome
Use a library of functions for transforming and composing promises
Promises/A+ specification - http://promises-aplus.github.io/promises-spec
@crichardson
Basic promise API
promise2 = promise1.then(fulfilledHandler, errorHandler, ...)
called when promise1 is fulfilled
returns a promise or value
resolved with outcome of callback
called when promise1 is rejected
returns a promise or value
About when.js
Rich API = Promises spec + use full
extensions
Creation:
when.defer()
when.reject()...
Combinators:
all, some, join, map, reduce
Other:
Calling non-promise code
timeout
....
https://github.com/cujojs/when
@crichardson
Simpler promise-based code
rest = require("rest")
@httpClient = rest.chain(mime).chain(errorCode);
getProductInfo : (productId) ->
@httpClient
path: "http://.../productinfo/" + productId
Returns a promise
No ugly callbacks
@crichardson
Simpler promise-based code
class ProductDetailsService
getProductDetails: (productId) ->
makeProductDetails = (productInfo, recommendations, reviews) ->
details =
productId: productId
productDetails: productInfo.entity
recommendations: recommendations.entity
reviews: reviews.entity
details
responses = [@getProductInfo(productId),
@getRecommendations(productId),
@getReviews(productId)]
all(responses).spread(makeProductDetails)
Array[Promise] Promise[Array]
@crichardson
Simpler promise-based code: HTTP
handler
getProductDetails = (req, res) ->
productId = req.params.productId
succeed = (productDetails) -> res.json(productDetails)
fail = (something) ->
res.send(500, JSON.stringify(something.entity || something))
productDetailsService.
getDetails(productId).
then(succeed, fail)
app.get('/productdetails/:productId', getProductDetails)
@crichardson
Writing robust client code
@crichardson
Implementing timeouts
timeout = require("when/timeout")
withTimeout = (promise) -> timeout(300, promise)
getProductDetails = (productId) -> ... withTimeout(client(...))
Creates a new promise
Original promise must complete within 300 msec
@crichardson
Recovering from failures
getRecommendations(productId).otherwise( -> {})
Invoked to return default value if getRecommendations()
fails
@crichardson
Limiting # of concurrent requests
ConcurrencyLimiter = require("./concurrencylimiter").ConcurrencyLimiter
limiter = new ConcurrencyLimiter(maxQueueSize = 100, maxConcurrency = 10)
getProductDetails = (productId) ->
... limiter.withLimit( -> client(...))
Homegrown code
@crichardson
Circuit breaker
CircuitBreaker = require("./circuitbreaker").CircuitBreaker
productCircuitBreaker = new CircuitBreaker()
getProductDetails = (productId) ->
... productCircuitBreaker.withCircuitBreaker( -> client(...))
Homegrown code
@crichardson
Putting it all together
getProductDetails: (productId) ->
...
responses = [@getProductInfo(productId),
@getRecommendations(productId).otherwise(() -> {}),
@getReviews(productId).otherwise(() -> {})]
all(responses).spread(succeed)
getProductInfo = (productId) ->
limiter.withLimit ->
productCircuitBreaker.withCircuitBreaker ->
withTimeout client
path: "http://..../productinfo/" + productd
@crichardson
Agenda
The need for concurrency
Simplifying concurrent code with Futures
Taming callback hell with JavaScript promises
Consuming asynchronous streams with Reactive Extensions
@crichardson
Let’s imagine you have a stream of trades
and
you need to calculate the rolling average
price of each stock
@crichardson
Spring Integration + Complex event
processing (CEP) engine is a good
choice
@crichardson
But where is the high-level abstraction
that solves this problem?
@crichardson
Future[List[T]]
Not applicable to infinite streams
@crichardson
Introducing Reactive Extensions (Rx)
The Reactive Extensions (Rx) is a library for composing
asynchronous and event-based programs using
observable sequences and LINQ-style query operators.
Using Rx, developers represent asynchronous data
streams with Observables , query asynchronous
data streams using LINQ operators , and .....
https://rx.codeplex.com/
@crichardson
About RxJava
Reactive Extensions (Rx) for the JVM
Implemented in Java
Adaptors for Scala, Groovy and Clojure
https://github.com/Netflix/RxJava
@crichardson
RxJava core concepts
class Observable<T> {
Subscription subscribe(Observer<T> observer)
...
}
interface Observer<T> {
void onNext(T args)
void onCompleted()
void onError(Throwable e)
}
Notifies
An asynchronous stream of
items
Used to unsubscribe
@crichardson
Comparing Observable to...
Observer pattern - similar but adds
Observer.onComplete()
Observer.onError()
Iterator pattern - mirror image
Push rather than pull
Future - similar but
Represents a stream of multiple values
@crichardson
So what?
@crichardson
Transforming Observables
class Observable<T> {
Observable<T> take(int n);
Observable<T> skip(int n);
<R> Observable<R> map(Func1<T,R> func)
<R> Observable<R> flatMap(Func1<T,Observable<R>> func)
Observable<T> filter(Func1<T,java.lang.Boolean> predicate)
...
}
Scala-collection style methods
@crichardson
Transforming observables
class Observable<T> {
<K> Observable<GroupedObservable<K,T>>
groupBy(Func1<T,K> keySelector)
...
}
Similar to Scala groupBy except results are emitted as items arrive
Stream of streams!
@crichardson
Combining observables
class Observable<T> {
static <R,T1,T2>
Observable<R> zip(Observable<T0> o1,
Observable<T1> o2,
Func2<T1,T2,R> reduceFunction)
...
}
Invoked with pairs of items from
o1 and o2
Stream of results from
reduceFunction
@crichardson
Creating observables from data
class Observable<T> {
static Observable<T> from(Iterable<T> iterable]);
static Observable<T> from(T items ...]);
static Observable<T> from(Future<T> future]);
...
}
@crichardson
Creating observables from event sources
Observable<T> o = Observable.create(
new SubscriberFunc<T> () {
Subscription onSubscribe(Observer<T> obs) {
... connect to event source....
return new Subscriber () {
void unsubscribe() { ... };
};
});
Called once for
each Observer
Called when
unsubscribing
Arranges to call obs.onNext/onComplete/...
@crichardson
Using Rx Observables instead of
Futures
@crichardson
Rx-based ProductInfoService
@Component
class ProductInfoService
override def getProductInfo(productId: Long) = {
val baseUrl = ...
val responseEntity =
asyncRestTemplate.getForEntity(baseUrl + "/productinfo/{productId}",
classOf[ProductInfo], productId)
toRxObservable(responseEntity).map {
(r : ResponseEntity[ProductInfo]) => r.getBody
}
}
@crichardson
ListenableFuture Observable
implicit def toRxObservable[T](future: ListenableFuture[T])
: Observable[T] = {
def create(o: Observer[T]) = {
future.addCallback(new ListenableFutureCallback[T] {
def onSuccess(result: T) {
o.onNext(result)
o.onCompleted()
}
def onFailure(t: Throwable) {
o.onError(t)
}
})
new Subscription {
def unsubscribe() {}
}
}
Observable.create(create _)
}
Supply single value
Indicate failure
Do nothing
@crichardson
Rx - ProductDetailsService
@Component
class ProductDetailsService @Autowired()
(productInfoService: ProductInfoService,
reviewService: ReviewService,
ecommendationService: RecommendationService) {
def getProductDetails(productId: Long) = {
val productInfo = productInfoService.getProductInfo(productId)
val recommendations =
recommendationService.getRecommendations(productId)
val reviews = reviewService.getReviews(productId)
Observable.zip(productInfo, recommendations, reviews,
(p : ProductInfo, r : Recommendations, rv : Reviews) =>
ProductDetails(p, r, rv))
}
}
Just like
Scala
Futures
@crichardson
Rx - ProductController
@Controller
class ProductController
@RequestMapping(Array("/productdetails/{productId}"))
@ResponseBody
def productDetails(@PathVariable productId: Long) =
toDeferredResult(productDetailsService.getProductDetails(productId))
@crichardson
Rx - Observable DeferredResult
implicit def toDeferredResult[T](observable : Observable[T]) = {
val result = new DeferredResult[T]
observable.subscribe(new Observer[T] {
def onCompleted() {}
def onError(e: Throwable) {
result.setErrorResult(e)
}
def onNext(r: T) {
result.setResult(r.asInstanceOf[T])
}
})
result
}
@crichardson
RxObservables vs. Futures
Much better than JDK 7 futures
Comparable to Scala Futures
Rx Scala code is slightly more verbose
@crichardson
Making this code robust
Hystrix works with Observables (and thread pools)
But
For event-driven code we are on our own
@crichardson
Back to the stream of Trades averaging
example...
@crichardson
AMQP messages Observables 1
<amqp:inbound-channel-adapter ... />
<int:channel id="inboundEventsChannel"/>
<int:service-activator
input-channel="inboundEventsChannel"
ref="amqpToObservableAdapter"
method="handleMessage"/>
@crichardson
AMQP messages Observables 2
class AmqpToObservableAdapter (actorRef : observerManager) {
def createObservable() =
Observable.create((o: Observer[_ >: String]) => {
observerManager ! Subscribe(o)
new Subscription {
override def unsubscribe() {
observerManager ! Unsubscribe(o)
}
}
})
def handleMessage(message : String) {
observerManager ! Message(message)
}
}
Manages and
notifies observers
@crichardson
Calculating averages
Observable<AveragePrice>
calculateAverages(Observable<Trade> trades) {
...
}
class Trade {
private String symbol;
private double price;
class AveragePrice {
private String symbol;
private
double averagePrice;
@crichardson
Using groupBy()
APPL : 401 IBM : 405 CAT : 405 APPL: 403
groupBy( (trade) => trade.symbol)
APPL : 401
IBM : 405
CAT : 405 ...
APPL: 403
Observable<GroupedObservable<String, Trade>>
Observable<Trade>
@crichardson
Using window()
APPL : 401 APPL : 405 APPL : 405 ...
APPL : 401 APPL : 405 APPL : 405
APPL : 405 APPL : 405 APPL : 403
APPL : 405 ...
window(...)
Observable<Trade>
Observable<Observable<Trade>>
N secs
N secs
M secs
@crichardson
Using reduce()
APPL : 402 APPL : 405 APPL : 405
APPL : 404
reduce(sumCalc) / length
Observable<Trade>
Observable<AveragePrice> Singleton
@crichardson
Using merge()
merge()
APPL : 401
IBM : 405
CAT : 405 ...
APPL: 403
APPL : 401 IBM : 405 CAT : 405 APPL: 403
Observable<Observable<AveragePrice>>
Observable<AveragePrice>
@crichardson
RxJS / NodeJS example
var rx = require("rx");
function tailFile (fileName) {
var self = this;
var o = rx.Observable.create(function (observer) {
var watcher = self.tail(fileName, function (line) {
observer.onNext(line);
});
return function () {
watcher.close();
}
});
return o.map(parseLogLine);
}
function parseLogLine(line) { ... }
@crichardson
Rx in the browser - implementing
completion
TextChanges(input)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliSeconds(10))
.Select(word=>Completions(word))
.Switch()
.Subscribe(ObserveChanges(output));
Your Mouse is a Database
http://queue.acm.org/detail.cfm?id=2169076
Ajax call returning
Observable
Change events Observable
Display completions
@crichardson
Summary
Consuming web services asynchronously is essential
Scala-style composable Futures are a powerful concurrency abstraction
Rx Observables are even more powerful
Rx Observables are a unifying abstraction for a wide variety of use cases
@crichardson
Questions?
@crichardson chris@chrisrichardson.net
http://plainoldobjects.com

Contenu connexe

Tendances

WebSocketでカメラの映像を共有してみた
WebSocketでカメラの映像を共有してみたWebSocketでカメラの映像を共有してみた
WebSocketでカメラの映像を共有してみたonozaty
 
PHPで並列処理する ライブラリを作った
PHPで並列処理する ライブラリを作ったPHPで並列処理する ライブラリを作った
PHPで並列処理する ライブラリを作ったHironobu Saitoh
 
MySQL Shell - The Best MySQL DBA Tool
MySQL Shell - The Best MySQL DBA ToolMySQL Shell - The Best MySQL DBA Tool
MySQL Shell - The Best MySQL DBA ToolMiguel Araújo
 
未来のプログラミング技術をUnityで -UniRx-
未来のプログラミング技術をUnityで -UniRx-未来のプログラミング技術をUnityで -UniRx-
未来のプログラミング技術をUnityで -UniRx-torisoup
 
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化규영 허
 
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...Miguel Araújo
 
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発ESFluteによるElasticsearchでのO/Rマッパーを用いた開発
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発Shinsuke Sugaya
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターンSoudai Sone
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
MySQL負荷分散の方法
MySQL負荷分散の方法MySQL負荷分散の方法
MySQL負荷分散の方法佐久本正太
 
今話題のいろいろなコンテナランタイムを比較してみた
今話題のいろいろなコンテナランタイムを比較してみた今話題のいろいろなコンテナランタイムを比較してみた
今話題のいろいろなコンテナランタイムを比較してみたKohei Tokunaga
 
診断ツールの使い方(Owasp zapの場合)
診断ツールの使い方(Owasp zapの場合)診断ツールの使い方(Owasp zapの場合)
診断ツールの使い方(Owasp zapの場合)shingo inafuku
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)Yoshitaka Kawashima
 
ClojureではじめるSTM入門
ClojureではじめるSTM入門ClojureではじめるSTM入門
ClojureではじめるSTM入門sohta
 
暗黒美夢王とEmacs
暗黒美夢王とEmacs暗黒美夢王とEmacs
暗黒美夢王とEmacsShougo
 
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話JustSystems Corporation
 

Tendances (20)

WebSocketでカメラの映像を共有してみた
WebSocketでカメラの映像を共有してみたWebSocketでカメラの映像を共有してみた
WebSocketでカメラの映像を共有してみた
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
 
PHPで並列処理する ライブラリを作った
PHPで並列処理する ライブラリを作ったPHPで並列処理する ライブラリを作った
PHPで並列処理する ライブラリを作った
 
MySQL Shell - The Best MySQL DBA Tool
MySQL Shell - The Best MySQL DBA ToolMySQL Shell - The Best MySQL DBA Tool
MySQL Shell - The Best MySQL DBA Tool
 
未来のプログラミング技術をUnityで -UniRx-
未来のプログラミング技術をUnityで -UniRx-未来のプログラミング技術をUnityで -UniRx-
未来のプログラミング技術をUnityで -UniRx-
 
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化
スケーラブル SwiftUI プロジェクトにおける実用的な TCA モジュラー化
 
Distributed fun with etcd
Distributed fun with etcdDistributed fun with etcd
Distributed fun with etcd
 
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...
MySQL InnoDB Cluster / ReplicaSet - Making Provisioning & Troubleshooting as ...
 
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発ESFluteによるElasticsearchでのO/Rマッパーを用いた開発
ESFluteによるElasticsearchでのO/Rマッパーを用いた開発
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
MySQL負荷分散の方法
MySQL負荷分散の方法MySQL負荷分散の方法
MySQL負荷分散の方法
 
今話題のいろいろなコンテナランタイムを比較してみた
今話題のいろいろなコンテナランタイムを比較してみた今話題のいろいろなコンテナランタイムを比較してみた
今話題のいろいろなコンテナランタイムを比較してみた
 
診断ツールの使い方(Owasp zapの場合)
診断ツールの使い方(Owasp zapの場合)診断ツールの使い方(Owasp zapの場合)
診断ツールの使い方(Owasp zapの場合)
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
ClojureではじめるSTM入門
ClojureではじめるSTM入門ClojureではじめるSTM入門
ClojureではじめるSTM入門
 
RESTfulとは
RESTfulとはRESTfulとは
RESTfulとは
 
OAuth 2.0のResource Serverの作り方
OAuth 2.0のResource Serverの作り方OAuth 2.0のResource Serverの作り方
OAuth 2.0のResource Serverの作り方
 
暗黒美夢王とEmacs
暗黒美夢王とEmacs暗黒美夢王とEmacs
暗黒美夢王とEmacs
 
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
 

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

Consuming web services asynchronously with Futures and Rx Observables (svcc, ...
Consuming web services asynchronously with Futures and Rx Observables (svcc, ...Consuming web services asynchronously with Futures and Rx Observables (svcc, ...
Consuming web services asynchronously with Futures and Rx Observables (svcc, ...Chris Richardson
 
Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Chris Richardson
 
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)Chris Richardson
 
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Chris Richardson
 
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Chris Richardson
 
NodeJS: the good parts? A skeptic’s view (devnexus2014)
NodeJS: the good parts? A skeptic’s view (devnexus2014)NodeJS: the good parts? A skeptic’s view (devnexus2014)
NodeJS: the good parts? A skeptic’s view (devnexus2014)Chris Richardson
 
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)Chris Richardson
 
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...Docker, Inc.
 
Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Chris Richardson
 
#JaxLondon keynote: Developing applications with a microservice architecture
#JaxLondon keynote: Developing applications with a microservice architecture#JaxLondon keynote: Developing applications with a microservice architecture
#JaxLondon keynote: Developing applications with a microservice architectureChris Richardson
 
Developing Applications with a Micro Service Architecture - Chris Richardson
Developing Applications with a Micro Service Architecture - Chris RichardsonDeveloping Applications with a Micro Service Architecture - Chris Richardson
Developing Applications with a Micro Service Architecture - Chris RichardsonJAXLondon2014
 
Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Chris Richardson
 
Developing applications with a microservice architecture (svcc)
Developing applications with a microservice architecture (svcc)Developing applications with a microservice architecture (svcc)
Developing applications with a microservice architecture (svcc)Chris Richardson
 
Building microservices with Scala, functional domain models and Spring Boot (...
Building microservices with Scala, functional domain models and Spring Boot (...Building microservices with Scala, functional domain models and Spring Boot (...
Building microservices with Scala, functional domain models and Spring Boot (...Chris Richardson
 
YOW2018 - Events and Commands: Developing Asynchronous Microservices
YOW2018 - Events and Commands: Developing Asynchronous MicroservicesYOW2018 - Events and Commands: Developing Asynchronous Microservices
YOW2018 - Events and Commands: Developing Asynchronous MicroservicesChris Richardson
 
Mucon: Not Just Events: Developing Asynchronous Microservices
Mucon: Not Just Events: Developing Asynchronous MicroservicesMucon: Not Just Events: Developing Asynchronous Microservices
Mucon: Not Just Events: Developing Asynchronous MicroservicesChris Richardson
 
An overview of the Eventuate Platform
An overview of the Eventuate PlatformAn overview of the Eventuate Platform
An overview of the Eventuate PlatformChris Richardson
 
Saturn 2018: Managing data consistency in a microservice architecture using S...
Saturn 2018: Managing data consistency in a microservice architecture using S...Saturn 2018: Managing data consistency in a microservice architecture using S...
Saturn 2018: Managing data consistency in a microservice architecture using S...Chris Richardson
 
Agile integration workshop Seattle
Agile integration workshop SeattleAgile integration workshop Seattle
Agile integration workshop SeattleJudy Breedlove
 
Overview of the Eventuate Tram Customers and Orders application
Overview of the Eventuate Tram Customers and Orders applicationOverview of the Eventuate Tram Customers and Orders application
Overview of the Eventuate Tram Customers and Orders applicationChris Richardson
 

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

Consuming web services asynchronously with Futures and Rx Observables (svcc, ...
Consuming web services asynchronously with Futures and Rx Observables (svcc, ...Consuming web services asynchronously with Futures and Rx Observables (svcc, ...
Consuming web services asynchronously with Futures and Rx Observables (svcc, ...
 
Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...Futures and Rx Observables: powerful abstractions for consuming web services ...
Futures and Rx Observables: powerful abstractions for consuming web services ...
 
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
 
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
 
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
Decompose That WAR! Architecting for Adaptability, Scalability, and Deployabi...
 
NodeJS: the good parts? A skeptic’s view (devnexus2014)
NodeJS: the good parts? A skeptic’s view (devnexus2014)NodeJS: the good parts? A skeptic’s view (devnexus2014)
NodeJS: the good parts? A skeptic’s view (devnexus2014)
 
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)
NodeJS: the good parts? A skeptic’s view (jmaghreb, jmaghreb2013)
 
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...
Microservices + Events + Docker = A Perfect Trio by Docker Captain Chris Rich...
 
Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)
 
#JaxLondon keynote: Developing applications with a microservice architecture
#JaxLondon keynote: Developing applications with a microservice architecture#JaxLondon keynote: Developing applications with a microservice architecture
#JaxLondon keynote: Developing applications with a microservice architecture
 
Developing Applications with a Micro Service Architecture - Chris Richardson
Developing Applications with a Micro Service Architecture - Chris RichardsonDeveloping Applications with a Micro Service Architecture - Chris Richardson
Developing Applications with a Micro Service Architecture - Chris Richardson
 
Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...Developing applications with a microservice architecture (SVforum, microservi...
Developing applications with a microservice architecture (SVforum, microservi...
 
Developing applications with a microservice architecture (svcc)
Developing applications with a microservice architecture (svcc)Developing applications with a microservice architecture (svcc)
Developing applications with a microservice architecture (svcc)
 
Building microservices with Scala, functional domain models and Spring Boot (...
Building microservices with Scala, functional domain models and Spring Boot (...Building microservices with Scala, functional domain models and Spring Boot (...
Building microservices with Scala, functional domain models and Spring Boot (...
 
YOW2018 - Events and Commands: Developing Asynchronous Microservices
YOW2018 - Events and Commands: Developing Asynchronous MicroservicesYOW2018 - Events and Commands: Developing Asynchronous Microservices
YOW2018 - Events and Commands: Developing Asynchronous Microservices
 
Mucon: Not Just Events: Developing Asynchronous Microservices
Mucon: Not Just Events: Developing Asynchronous MicroservicesMucon: Not Just Events: Developing Asynchronous Microservices
Mucon: Not Just Events: Developing Asynchronous Microservices
 
An overview of the Eventuate Platform
An overview of the Eventuate PlatformAn overview of the Eventuate Platform
An overview of the Eventuate Platform
 
Saturn 2018: Managing data consistency in a microservice architecture using S...
Saturn 2018: Managing data consistency in a microservice architecture using S...Saturn 2018: Managing data consistency in a microservice architecture using S...
Saturn 2018: Managing data consistency in a microservice architecture using S...
 
Agile integration workshop Seattle
Agile integration workshop SeattleAgile integration workshop Seattle
Agile integration workshop Seattle
 
Overview of the Eventuate Tram Customers and Orders application
Overview of the Eventuate Tram Customers and Orders applicationOverview of the Eventuate Tram Customers and Orders application
Overview of the Eventuate Tram Customers and Orders application
 

Plus de Chris Richardson

The microservice architecture: what, why, when and how?
The microservice architecture: what, why, when and how?The microservice architecture: what, why, when and how?
The microservice architecture: what, why, when and how?Chris Richardson
 
More the merrier: a microservices anti-pattern
More the merrier: a microservices anti-patternMore the merrier: a microservices anti-pattern
More the merrier: a microservices anti-patternChris Richardson
 
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...Chris Richardson
 
Dark Energy, Dark Matter and the Microservices Patterns?!
Dark Energy, Dark Matter and the Microservices Patterns?!Dark Energy, Dark Matter and the Microservices Patterns?!
Dark Energy, Dark Matter and the Microservices Patterns?!Chris Richardson
 
Dark energy, dark matter and microservice architecture collaboration patterns
Dark energy, dark matter and microservice architecture collaboration patternsDark energy, dark matter and microservice architecture collaboration patterns
Dark energy, dark matter and microservice architecture collaboration patternsChris Richardson
 
Scenarios_and_Architecture_SkillsMatter_April_2022.pdf
Scenarios_and_Architecture_SkillsMatter_April_2022.pdfScenarios_and_Architecture_SkillsMatter_April_2022.pdf
Scenarios_and_Architecture_SkillsMatter_April_2022.pdfChris Richardson
 
Using patterns and pattern languages to make better architectural decisions
Using patterns and pattern languages to make better architectural decisions Using patterns and pattern languages to make better architectural decisions
Using patterns and pattern languages to make better architectural decisions Chris Richardson
 
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...Chris Richardson
 
Events to the rescue: solving distributed data problems in a microservice arc...
Events to the rescue: solving distributed data problems in a microservice arc...Events to the rescue: solving distributed data problems in a microservice arc...
Events to the rescue: solving distributed data problems in a microservice arc...Chris Richardson
 
A pattern language for microservices - June 2021
A pattern language for microservices - June 2021 A pattern language for microservices - June 2021
A pattern language for microservices - June 2021 Chris Richardson
 
QConPlus 2021: Minimizing Design Time Coupling in a Microservice Architecture
QConPlus 2021: Minimizing Design Time Coupling in a Microservice ArchitectureQConPlus 2021: Minimizing Design Time Coupling in a Microservice Architecture
QConPlus 2021: Minimizing Design Time Coupling in a Microservice ArchitectureChris Richardson
 
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Chris Richardson
 
Designing loosely coupled services
Designing loosely coupled servicesDesigning loosely coupled services
Designing loosely coupled servicesChris Richardson
 
Microservices - an architecture that enables DevOps (T Systems DevOps day)
Microservices - an architecture that enables DevOps (T Systems DevOps day)Microservices - an architecture that enables DevOps (T Systems DevOps day)
Microservices - an architecture that enables DevOps (T Systems DevOps day)Chris Richardson
 
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...Chris Richardson
 
Decompose your monolith: Six principles for refactoring a monolith to microse...
Decompose your monolith: Six principles for refactoring a monolith to microse...Decompose your monolith: Six principles for refactoring a monolith to microse...
Decompose your monolith: Six principles for refactoring a monolith to microse...Chris Richardson
 
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...Chris Richardson
 
#DevNexus202 Decompose your monolith
#DevNexus202 Decompose your monolith#DevNexus202 Decompose your monolith
#DevNexus202 Decompose your monolithChris Richardson
 
JFokus: Cubes, Hexagons, Triangles, and More: Understanding Microservices
JFokus: Cubes, Hexagons, Triangles, and More: Understanding MicroservicesJFokus: Cubes, Hexagons, Triangles, and More: Understanding Microservices
JFokus: Cubes, Hexagons, Triangles, and More: Understanding MicroservicesChris Richardson
 
Decompose your monolith: strategies for migrating to microservices (Tide)
Decompose your monolith: strategies for migrating to microservices (Tide)Decompose your monolith: strategies for migrating to microservices (Tide)
Decompose your monolith: strategies for migrating to microservices (Tide)Chris Richardson
 

Plus de Chris Richardson (20)

The microservice architecture: what, why, when and how?
The microservice architecture: what, why, when and how?The microservice architecture: what, why, when and how?
The microservice architecture: what, why, when and how?
 
More the merrier: a microservices anti-pattern
More the merrier: a microservices anti-patternMore the merrier: a microservices anti-pattern
More the merrier: a microservices anti-pattern
 
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...
YOW London - Considering Migrating a Monolith to Microservices? A Dark Energy...
 
Dark Energy, Dark Matter and the Microservices Patterns?!
Dark Energy, Dark Matter and the Microservices Patterns?!Dark Energy, Dark Matter and the Microservices Patterns?!
Dark Energy, Dark Matter and the Microservices Patterns?!
 
Dark energy, dark matter and microservice architecture collaboration patterns
Dark energy, dark matter and microservice architecture collaboration patternsDark energy, dark matter and microservice architecture collaboration patterns
Dark energy, dark matter and microservice architecture collaboration patterns
 
Scenarios_and_Architecture_SkillsMatter_April_2022.pdf
Scenarios_and_Architecture_SkillsMatter_April_2022.pdfScenarios_and_Architecture_SkillsMatter_April_2022.pdf
Scenarios_and_Architecture_SkillsMatter_April_2022.pdf
 
Using patterns and pattern languages to make better architectural decisions
Using patterns and pattern languages to make better architectural decisions Using patterns and pattern languages to make better architectural decisions
Using patterns and pattern languages to make better architectural decisions
 
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...
iSAQB gathering 2021 keynote - Architectural patterns for rapid, reliable, fr...
 
Events to the rescue: solving distributed data problems in a microservice arc...
Events to the rescue: solving distributed data problems in a microservice arc...Events to the rescue: solving distributed data problems in a microservice arc...
Events to the rescue: solving distributed data problems in a microservice arc...
 
A pattern language for microservices - June 2021
A pattern language for microservices - June 2021 A pattern language for microservices - June 2021
A pattern language for microservices - June 2021
 
QConPlus 2021: Minimizing Design Time Coupling in a Microservice Architecture
QConPlus 2021: Minimizing Design Time Coupling in a Microservice ArchitectureQConPlus 2021: Minimizing Design Time Coupling in a Microservice Architecture
QConPlus 2021: Minimizing Design Time Coupling in a Microservice Architecture
 
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
Mucon 2021 - Dark energy, dark matter: imperfect metaphors for designing micr...
 
Designing loosely coupled services
Designing loosely coupled servicesDesigning loosely coupled services
Designing loosely coupled services
 
Microservices - an architecture that enables DevOps (T Systems DevOps day)
Microservices - an architecture that enables DevOps (T Systems DevOps day)Microservices - an architecture that enables DevOps (T Systems DevOps day)
Microservices - an architecture that enables DevOps (T Systems DevOps day)
 
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...
DDD SoCal: Decompose your monolith: Ten principles for refactoring a monolith...
 
Decompose your monolith: Six principles for refactoring a monolith to microse...
Decompose your monolith: Six principles for refactoring a monolith to microse...Decompose your monolith: Six principles for refactoring a monolith to microse...
Decompose your monolith: Six principles for refactoring a monolith to microse...
 
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...
TDC2020 - The microservice architecture: enabling rapid, reliable, frequent a...
 
#DevNexus202 Decompose your monolith
#DevNexus202 Decompose your monolith#DevNexus202 Decompose your monolith
#DevNexus202 Decompose your monolith
 
JFokus: Cubes, Hexagons, Triangles, and More: Understanding Microservices
JFokus: Cubes, Hexagons, Triangles, and More: Understanding MicroservicesJFokus: Cubes, Hexagons, Triangles, and More: Understanding Microservices
JFokus: Cubes, Hexagons, Triangles, and More: Understanding Microservices
 
Decompose your monolith: strategies for migrating to microservices (Tide)
Decompose your monolith: strategies for migrating to microservices (Tide)Decompose your monolith: strategies for migrating to microservices (Tide)
Decompose your monolith: strategies for migrating to microservices (Tide)
 

Dernier

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Jeffrey Haguewood
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...BookNet Canada
 
A Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxA Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxAna-Maria Mihalceanu
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 

Dernier (20)

Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
Transcript: New from BookNet Canada for 2024: BNC SalesData and LibraryData -...
 
A Glance At The Java Performance Toolbox
A Glance At The Java Performance ToolboxA Glance At The Java Performance Toolbox
A Glance At The Java Performance Toolbox
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 

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

  • 1. @crichardson Consuming web services asynchronously with Futures and Rx Observables Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com
  • 2. @crichardson Presentation goal Learn how to use (Scala) Futures and Rx Observables to write simple yet robust and scalable concurrent code
  • 9. @crichardson Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions
  • 10. @crichardson Let’s imagine you are building an online store
  • 15. @crichardson Application architecture Product Info Service Desktop browser Native mobile client REST REST REST Recomendation Service Review Service Front end server API gatewayREST Mobile browser Web Application HTML
  • 16. @crichardson Handling getProductDetails() Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails()
  • 17. @crichardson Handling getProductDetails() - sequentially Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() Higher response time :-(
  • 18. @crichardson Handling getProductDetails() - in parallel Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() Lower response time :-)
  • 19. @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
  • 20. @crichardson The front-end server must handle partial failure of backend services Front-end server Product Info Service Recommendations Service Review Service getProductInfo() getRecommendations() getReviews() getProductDetails() X How to provide a good user experience?
  • 21. @crichardson Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions
  • 22. @crichardson Futures are a great concurrency abstraction http://en.wikipedia.org/wiki/Futures_and_promises
  • 24. @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.
  • 25. @crichardson REST client using Spring @Async @Component class ProductInfoServiceImpl extends ProducInfoService { val restTemplate : RestTemplate = ... @Async def getProductInfo(productId: Long) = { new AsyncResult(restTemplate.getForObject(....)...) } } Execute asynchronously in thread pool A Future containing a value trait ProductInfoService { def getProductInfo(productId: Long): java.util.concurrent.Future[ProductInfo] }
  • 26. @crichardson ProductDetailsService @Component class ProductDetailsService @Autowired()(productInfoService: ProductInfoService, reviewService: ReviewService, recommendationService: RecommendationService) { def getProductDetails(productId: Long): ProductDetails = { val productInfoFuture = productInfoService.getProductInfo(productId) } } val recommendationsFuture = recommendationService.getRecommendations(productId) val reviewsFuture = reviewService.getReviews(productId) val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS) val recommendations = recommendationsFuture.get(10, TimeUnit.MILLISECONDS) val reviews = reviewsFuture.get(10, TimeUnit.MILLISECONDS) ProductDetails(productInfo, recommendations, reviews)
  • 27. @crichardson ProductController @Controller class ProductController @Autowired()(productDetailsService : ProductDetailsService) { @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = productDetailsService.getProductDetails(productId)
  • 28. @crichardson Not bad but... val productInfo = productInfoFuture.get(300, TimeUnit.MILLISECONDS) Blocks Tomcat thread until Future completes Not so scalable :-(
  • 29. @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
  • 30. @crichardson Better: Futures with callbacks no blocking! val f : Future[Int] = Future { ... } f onSuccess { case x : Int => println(x) } f onFailure { case e : Exception => println("exception thrown") } Guava ListenableFutures, Spring 4 ListenableFuture Java 8 CompletableFuture, Scala Futures
  • 31. @crichardson Even better: Composable Futures val f1 = Future { ... ; 1 } val f2 = Future { ... ; 2 } val f4 = f2.map(_ * 2) assertEquals(4, Await.result(f4, 1 second)) val fzip = f1 zip f2 assertEquals((1, 2), Await.result(fzip, 1 second)) Transforms Future Combines two futures Scala, Java 8 CompletableFuture (partially)
  • 32. @crichardson Scala futures are Monads def callB() : Future[...] = ... def callC() : Future[...] = ... def callD() : Future[...] = ... val result = for { (b, c) <- callB() zip callC(); d <- callD(b, c) } yield d result onSuccess { .... } Two calls execute in parallel And then invokes D Get the result of D
  • 33. @crichardson Scala Future + RestTemplate import scala.concurrent.Future @Component class ProductInfoService { def getProductInfo(productId: Long): Future[ProductInfo] = { Future { restTemplate.getForObject(....) } } } Executes in thread pool Scala Future
  • 34. @crichardson Scala Future + RestTemplate class ProductDetailsService @Autowired()(....) { def getProductDetails(productId: Long) = { val productInfoFuture = productInfoService.getProductInfo(productId) val recommendationsFuture = recommendationService.getRecommendations(productId) val reviewsFuture = reviewService.getReviews(productId) for (((productInfo, recommendations), reviews) <- productInfoFuture zip recommendationsFuture zip reviewsFuture) yield ProductDetails(productInfo, recommendations, reviews) } } Non-blocking!
  • 35. @crichardson Async Spring MVC + Scala Futures @Controller class ProductController ... { @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = { val productDetails = productDetailsService.getProductDetails(productId) val result = new DeferredResult[ProductDetails] productDetails onSuccess { case r => result.setResult(r) } productDetails onFailure { case t => result.setErrorResult(t) } result } Convert Scala Future to Spring MVC DeferredResult
  • 36. @crichardson Servlet layer is asynchronous but the backend uses thread pools Need event-driven REST client
  • 37. @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
  • 38. @crichardson Reactor pattern structure Event Handler handle_event(type) get_handle() Initiation Dispatcher handle_events() register_handler(h) select(handlers) for each h in handlers h.handle_event(type) end loop handle Synchronous Event Demultiplexer select() owns notifies uses handlers Application creates
  • 39. @crichardson Java NIO Selectors = Reactor pattern But that’s super low-level :-(
  • 40. @crichardson New in Spring 4 Mirrors RestTemplate Methods return a ListenableFuture = JDK 7 Future + callback methods Can use HttpComponents NIO-based AsyncHttpClient Spring AsyncRestTemplate
  • 41. @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
  • 42. @crichardson Converting ListenableFuture to Scala Future implicit def toScalaFuture[T](f : ListenableFuture[T]) : Future[T] = { val p = promise[T] f.addCallback(new ListenableFutureCallback[T] { def onSuccess(result: T) { p.success(result)} def onFailure(t: Throwable) { p.failure(t) } }) p.future } The producer side of Scala Futures Supply outcome Return future
  • 43. @crichardson Now everything is non-blocking :-)
  • 44. @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
  • 45. @crichardson Fault tolerance at Netflix Network timeouts and retries Invoke remote services via a bounded thread pool Use the Circuit Breaker pattern On failure: return default/cached data return error to caller Implementation: https://github.com/Netflix/Hystrix http://techblog.netflix.com/2012/02/fault-tolerance-in-high-volume.html
  • 46. @crichardson Using Hystrix @Component class ProductInfoServiceImpl extends ProductInfoService { val restTemplate = RestTemplateFactory.makeRestTemplate() val baseUrl = ... class GetProductInfoCommand(productId: Long)extends HystrixCommand[ProductInfo](....) { override def run() = restTemplate. getForEntity("{baseUrl}/productinfo/{productId}", classOf[ProductInfo], baseUrl, productId).getBody } def getProductInfoUsingHystrix(productId: Long) : Future[ProductInfo] = { new GetProductInfoCommand(productId).queue() } } Runs in thread pool Returns JDK Future
  • 47. @crichardson But how to accomplish this with event- driven code
  • 48. @crichardson How to handling partial failures? productDetailsFuture zip recommendationsFuture zip reviewsFuture Fails if any Future has failed
  • 49. @crichardson Handling partial failures val recommendationsFuture = recommendationService. getRecommendations(userId,productId). recover { case _ => Recommendations(List()) } “catch-like” Maps Throwable to value
  • 50. @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:-(
  • 51. @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
  • 52. @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() }
  • 53. @crichardson Limiting # of simultaneous requests val limiter = new ConcurrencyLimiter(maxConcurrentRequests=10, maxQueueSize=30) val resultFuture = limiter.withLimit { asynchronousOperationReturningFuture() } class ConcurrencyLimiter ... val concurrencyManager : ActorRef = ... def withLimit[T](body : => Future[T])(...) = (concurrencyManager ? ConcurrentExecutionManager.Request { () => body }).mapTo[T]
  • 54. @crichardson Putting it all together @Component class ProductInfoServiceImpl @Autowired()(...) extends ProductService { val limiter = new ConcurrencyLimiter(...) val breaker = new CircuitBreaker(...) override def getProductInfo(productId: Long) = { ... breaker.withCircuitBreaker { limiter.withLimit { TimeoutFuture { ... AsyncRestTemplate.get ... } } } }
  • 55. @crichardson Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions
  • 57. @crichardson Why solve this problem for JavaScript? Browser invokes web services Implement front-end server/API gateway using NodeJS!
  • 60. @crichardson Asynchronous JavaScript code = callback hell Scenarios: Sequential: A B C Fork and join: A and B C Code quickly becomes very messy
  • 61. @crichardson Callback-based HTTP client request = require("request") handler = (error, clientResponse, body) -> if clientResponse.statusCode != 200 // ERROR else // SUCCESS request("http://.../productdetails/" + productId, handler)
  • 62. @crichardson Messy callback code getProductDetails = (req, res) -> productId = req.params.productId result = {productId: productId} makeHandler = (key) -> (error, clientResponse, body) -> if clientResponse.statusCode != 200 res.status(clientResponse.statusCode) res.write(body) res.end() else result[key] = JSON.parse(body) if (result.productInfo and result.recommendations and result.reviews) res.json(result) request("http://localhost:3000/productdetails/" + productId, makeHandler("productInfo")) request("http://localhost:3000/recommendations/" + productId, makeHandler('recommendations')) request("http://localhost:3000/reviews/" + productId, makeHandler('reviews')) app.get('/productinfo/:productId', getProductInfo) Returns a callback function Have all three requests completed?
  • 63. @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
  • 64. @crichardson Basic promise API promise2 = promise1.then(fulfilledHandler, errorHandler, ...) called when promise1 is fulfilled returns a promise or value resolved with outcome of callback called when promise1 is rejected returns a promise or value
  • 65. About when.js Rich API = Promises spec + use full extensions Creation: when.defer() when.reject()... Combinators: all, some, join, map, reduce Other: Calling non-promise code timeout .... https://github.com/cujojs/when
  • 66. @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
  • 67. @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]
  • 68. @crichardson Simpler promise-based code: HTTP handler getProductDetails = (req, res) -> productId = req.params.productId succeed = (productDetails) -> res.json(productDetails) fail = (something) -> res.send(500, JSON.stringify(something.entity || something)) productDetailsService. getDetails(productId). then(succeed, fail) app.get('/productdetails/:productId', getProductDetails)
  • 70. @crichardson Implementing timeouts timeout = require("when/timeout") withTimeout = (promise) -> timeout(300, promise) getProductDetails = (productId) -> ... withTimeout(client(...)) Creates a new promise Original promise must complete within 300 msec
  • 71. @crichardson Recovering from failures getRecommendations(productId).otherwise( -> {}) Invoked to return default value if getRecommendations() fails
  • 72. @crichardson Limiting # of concurrent requests ConcurrencyLimiter = require("./concurrencylimiter").ConcurrencyLimiter limiter = new ConcurrencyLimiter(maxQueueSize = 100, maxConcurrency = 10) getProductDetails = (productId) -> ... limiter.withLimit( -> client(...)) Homegrown code
  • 73. @crichardson Circuit breaker CircuitBreaker = require("./circuitbreaker").CircuitBreaker productCircuitBreaker = new CircuitBreaker() getProductDetails = (productId) -> ... productCircuitBreaker.withCircuitBreaker( -> client(...)) Homegrown code
  • 74. @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
  • 75. @crichardson Agenda The need for concurrency Simplifying concurrent code with Futures Taming callback hell with JavaScript promises Consuming asynchronous streams with Reactive Extensions
  • 76. @crichardson Let’s imagine you have a stream of trades and you need to calculate the rolling average price of each stock
  • 77. @crichardson Spring Integration + Complex event processing (CEP) engine is a good choice
  • 78. @crichardson But where is the high-level abstraction that solves this problem?
  • 80. @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/
  • 81. @crichardson About RxJava Reactive Extensions (Rx) for the JVM Implemented in Java Adaptors for Scala, Groovy and Clojure https://github.com/Netflix/RxJava
  • 82. @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
  • 83. @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
  • 85. @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
  • 86. @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!
  • 87. @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
  • 88. @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]); ... }
  • 89. @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/...
  • 90. @crichardson Using Rx Observables instead of Futures
  • 91. @crichardson Rx-based ProductInfoService @Component class ProductInfoService override def getProductInfo(productId: Long) = { val baseUrl = ... val responseEntity = asyncRestTemplate.getForEntity(baseUrl + "/productinfo/{productId}", classOf[ProductInfo], productId) toRxObservable(responseEntity).map { (r : ResponseEntity[ProductInfo]) => r.getBody } }
  • 92. @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
  • 93. @crichardson Rx - ProductDetailsService @Component class ProductDetailsService @Autowired() (productInfoService: ProductInfoService, reviewService: ReviewService, ecommendationService: RecommendationService) { def getProductDetails(productId: Long) = { val productInfo = productInfoService.getProductInfo(productId) val recommendations = recommendationService.getRecommendations(productId) val reviews = reviewService.getReviews(productId) Observable.zip(productInfo, recommendations, reviews, (p : ProductInfo, r : Recommendations, rv : Reviews) => ProductDetails(p, r, rv)) } } Just like Scala Futures
  • 94. @crichardson Rx - ProductController @Controller class ProductController @RequestMapping(Array("/productdetails/{productId}")) @ResponseBody def productDetails(@PathVariable productId: Long) = toDeferredResult(productDetailsService.getProductDetails(productId))
  • 95. @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 }
  • 96. @crichardson RxObservables vs. Futures Much better than JDK 7 futures Comparable to Scala Futures Rx Scala code is slightly more verbose
  • 97. @crichardson Making this code robust Hystrix works with Observables (and thread pools) But For event-driven code we are on our own
  • 98. @crichardson Back to the stream of Trades averaging example...
  • 99. @crichardson AMQP messages Observables 1 <amqp:inbound-channel-adapter ... /> <int:channel id="inboundEventsChannel"/> <int:service-activator input-channel="inboundEventsChannel" ref="amqpToObservableAdapter" method="handleMessage"/>
  • 100. @crichardson AMQP messages Observables 2 class AmqpToObservableAdapter (actorRef : observerManager) { def createObservable() = Observable.create((o: Observer[_ >: String]) => { observerManager ! Subscribe(o) new Subscription { override def unsubscribe() { observerManager ! Unsubscribe(o) } } }) def handleMessage(message : String) { observerManager ! Message(message) } } Manages and notifies observers
  • 101. @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;
  • 102. @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>
  • 103. @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
  • 104. @crichardson Using reduce() APPL : 402 APPL : 405 APPL : 405 APPL : 404 reduce(sumCalc) / length Observable<Trade> Observable<AveragePrice> Singleton
  • 105. @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>
  • 106. @crichardson RxJS / NodeJS example var rx = require("rx"); function tailFile (fileName) { var self = this; var o = rx.Observable.create(function (observer) { var watcher = self.tail(fileName, function (line) { observer.onNext(line); }); return function () { watcher.close(); } }); return o.map(parseLogLine); } function parseLogLine(line) { ... }
  • 107. @crichardson Rx in the browser - implementing completion TextChanges(input) .DistinctUntilChanged() .Throttle(TimeSpan.FromMilliSeconds(10)) .Select(word=>Completions(word)) .Switch() .Subscribe(ObserveChanges(output)); Your Mouse is a Database http://queue.acm.org/detail.cfm?id=2169076 Ajax call returning Observable Change events Observable Display completions
  • 108. @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