Async Microservices 
with Finagle 
Vladimir Kostyukov 
http://vkostyukov.ru
Asynchronous 
Protocol-Agnostic 
Full-Stack RPC 
2
Adopters 
3
Built atop of Netty 
(#1 Non-Blocking I/O for JVM) 
4
Finagle - 
Netty in a functional setting 
5
Building Blocks: 
Services + Futures + Filters 
6
trait Service[-Req, +Rep] extends (Req => Future[Rep]) 
7
Service-Oriented 
rather then 
Stream-Oriented 
8
// TODO: Don't forget to remove it in production. 
object GetDeveloperPromotionDate extends Service[Developer, Date] { 
def apply(req: Developer) = Future.never 
} 
val date: Future[Date] = GetDeveloperPromotionDate(Developer.Myself) 
9
1 val respond = new Service[HttpRequest, HttpResponse] { 
2 def apply(req: HttpRequest) = { 
3 val rep = new DefaultHttpResponse(HttpVersion.HTTP_1_1, 
4 HttpResponseStatus.OK) 
5 rep.setContentString(req.getUri()) 
6 Future.value(rep) 
7 } 
8 } 
9 
10 Await.ready(Http.serve(":8080", respond) 
10
Servers and Clients 
talk to each other via services 
11
1 val to = Http.newService("google.com") 
2 
3 val proxy = new Service[HttpRequest, HttpResponse] { 
4 def apply(req: HttpRequest) = to(req) 
5 } 
6 
7 Await.ready(Http.serve(":8080", proxy) 
12
Are there high-order services? 
13
14 
Client 
Service 
Server 
Filter Filter Filter Service
// ReqIn -> Service(ReqOut -> RepIn) -> RepOut 
trait Filter[-ReqIn, +RepOut, +ReqOut, -RepIn] 
extends ((ReqIn, Service[ReqOut, RepIn]) => Future[RepOut]) 
15
// A filter that does nothing. 
def identity[Req, Rep] = new Filter[Req, Rep, Req, Rep] { 
def apply(req: Req, service: Service[Req, Rep]) = service(req) 
} 
val auth = identity[HttpRequest, HttpResponse] 
16
Filters are type-safe! 
17
A Type-Safe Input Filter 
1 object TurnAIntoB extends Filter[A, Rep, B, Rep] { 
2 def apply(req: A, service: Service[B, Rep]): Future[Rep] = 
3 service(req.toB) 
4 } 
5 
6 val serviceOfB: Service[B, Rep] = ... 
7 val serviceOfA: Service[A, Rep] = TurnAIntoB andThen serviceOfA 
18
A Type-Safe Output Filter 
1 object TurnAIntoB extends Filter[Req, B, Req, A] { 
2 def apply(req: Req, service: Service[Req, A]): Future[B] = 
3 service(req) map { a => a.toB } 
4 } 
5 
6 val serviceOfA: Service[Req, A] = ... 
7 val serviceOfB: Service[Req, B] = TurnAIntoB andThen serviceOfA 
19
Case Study: TimeOut Filter 
1 def timeout[Req, Rep](timeout: Duration)(implicit timer: Timer) = 
2 new SimpleFilter[Req, Rep] { 
3 def apply(req: Req, service: Service[Req, Rep]) = 
4 service(req).within(timer, timeout) 
5 } 
6 
7 val handleExceptions = new SimpleFilter[Req, Rep] { 
8 def apply(req: Req, service: Service[Req, Rep]) = 
9 service(req) handle { 
10 case t: TimeOutException => Future.value(defaultRep) 
11 } 
12 } 
13 
14 val respond = new Service[Req, Rep] { ... } 
15 // We guarantee 3 seconds response time. 
16 val backend = handleExceptions andThen 
17 timeout(3.seconds) andThen 
18 respond 
20
Case Study: OAuth2Filter 
1 class OAuth2Filter[U](dataHandler: DataHandler[U]) 
2 extends Filter[HttpRequest, HttpResponse, OAuth2Request[U], HttpResponse] 
3 with OAuth2 with OAuthErrorHandler { 
4 
5 def handleError(e: OAuthError) = e.toHttpResponse 
6 def apply(req: HttpRequest, service: Service[OAuth2Request[U], HttpResponse]) = 
7 authorize(req, dataHandler) flatMap { authInfo => 
8 service(OAuth2Request(authInfo, req)) 
9 } handle { 
10 case e: OAuthError => handleError(e) 
11 } 
12 } 
13 
14 val authorize = new OAuth2Filter(...) 
15 val respond: Service[OAuth2Request[U], HttpResponse] = ??? 
16 val backend: Service[HttpRequest, HttpResponse] = authorize andThen respond 
21
Future is a monad! 
22
Abstraction: Fibonacci Calculator 
1 trait FibonacciCalculator { 
2 val Zero = BigInt(0) 
3 val One = BigInt(1) 
4 val Two = BigInt(2) 
5 
6 def calculate(n: BigInt): Future[BigInt] 
7 } 
23
Sequential Composition: map & flatMap 
1 trait Future[+A] { 
2 def flatMap[B](f: A => Future[B]): Future[B] 
3 def map[B](f: A => B): Future[B] 
4 } 
24
FlatMap Power 
1 val ab: Service[A, B] = ??? 
2 val bc: Service[B, C] = ??? 
3 val cd: Service[C, D] = ??? 
4 
5 val req: A = ??? 
6 val rep: Future[D] = ab(req) flatMap bc flatMap cd 
25
Sequential Composition: map & flatMap 
1 object FlatMapFibonacciCalculator extends FibonacciCalculator { 
2 def calculate(n: BigInt): Future[BigInt] = 
3 if (n == Zero || n == One) Future.value(n) 
4 else calculate(n - One) flatMap { a => 
5 calculate(n - Two) flatMap { b => Future.value(a + b) } 
6 } 
7 } 
8 
9 object MapFibonacciCalculator extends FibonacciCalculator { 
10 def calculate(n: BigInt): Future[BigInt] = 
11 if (n == Zero || n == One) Future.value(n) 
12 else calculate(n - One) map { a => 
13 calculate(n - Two) map { b => a + b } 
14 } 
15 } 
26
Sequential Composition: for-comprehension 
1 object ForFibonacciCalculator extends FibonacciCalculator { 
2 def calculate(n: BigInt): Future[BigInt] = 
3 if (n == Zero || n == One) Future.value(n) 
4 else for { 
5 a <- calculate(n - One) 
6 b <- calculate(n - Two) 
7 } yield a + b 
8 } 
27
Concurrent Composition: collect & select 
1 object Future { 
2 def collect[A](fs: Seq[Future[A]]): Future[Seq[A]] 
3 def select[A](fs: Seq[Future[A]]): Future[A] 
4 } 
28
Concurrent Composition: collect 
1 class FanoutFibonacciCalculator( 
2 left: FibonacciCalculator, 
3 right: FibonacciCalculator) extends FibonacciCalculator { 
4 
5 def calculate(n: BigInt): Future[BigInt] = 
6 if (n == Zero) || n == One) Future.value(n) 
7 else { 
8 val seq = Seq(left.calculate(n - One), right.calculate(n - Two)) 
9 Future.collect(seq) map { _.sum } 
10 } 
11 } 
29
Concurrent Composition: select 
1 class SelectFibonacciCalculator(seq: Seq[FibonacciCalculator]) 
2 extends FibonacciCalculator { 
3 
4 def calculate(n: BigInt): Future[BigInt] = { 
5 val futures: Seq[Future[BigInt]] = seq map { _.calculate(n) } 
6 Future.select(futures) 
7 } 
8 } 
30
Futures should be 
chained asynchronously 
31
Do Not Await 
// Asynchronous operation. 
val f = service(req) 
// Blocking operation. 
Await.result(f) 
32
Involving Side-Effects 
// Asynchronous operation. 
val f = service(req) 
! 
f onSuccess { rep => println("Got the value: " + rep) } 
onFailure { t => t.printStackTrace() } 
33
Finagle is a non-blocking glue for 
services that implement 
different protocols 
34
Finagle is extremely good at 
gluing things that work 
with different speed 
35
References 
§ http://twitter.github.io/finagle/ 
! 
§ http://vkostyukov.ru/posts/finagle-your-fibonacci-calculation/ 
! 
§ https://github.com/finagle/finch 
! 
§ https://github.com/finagle/finagle-oauth2 
36
Stay Finagled! 
! 
And drop your feedbacks to 
@vkostyukov 
37

Async Microservices with Twitter's Finagle

  • 1.
    Async Microservices withFinagle Vladimir Kostyukov http://vkostyukov.ru
  • 2.
  • 3.
  • 4.
    Built atop ofNetty (#1 Non-Blocking I/O for JVM) 4
  • 5.
    Finagle - Nettyin a functional setting 5
  • 6.
    Building Blocks: Services+ Futures + Filters 6
  • 7.
    trait Service[-Req, +Rep]extends (Req => Future[Rep]) 7
  • 8.
    Service-Oriented rather then Stream-Oriented 8
  • 9.
    // TODO: Don'tforget to remove it in production. object GetDeveloperPromotionDate extends Service[Developer, Date] { def apply(req: Developer) = Future.never } val date: Future[Date] = GetDeveloperPromotionDate(Developer.Myself) 9
  • 10.
    1 val respond= new Service[HttpRequest, HttpResponse] { 2 def apply(req: HttpRequest) = { 3 val rep = new DefaultHttpResponse(HttpVersion.HTTP_1_1, 4 HttpResponseStatus.OK) 5 rep.setContentString(req.getUri()) 6 Future.value(rep) 7 } 8 } 9 10 Await.ready(Http.serve(":8080", respond) 10
  • 11.
    Servers and Clients talk to each other via services 11
  • 12.
    1 val to= Http.newService("google.com") 2 3 val proxy = new Service[HttpRequest, HttpResponse] { 4 def apply(req: HttpRequest) = to(req) 5 } 6 7 Await.ready(Http.serve(":8080", proxy) 12
  • 13.
  • 14.
    14 Client Service Server Filter Filter Filter Service
  • 15.
    // ReqIn ->Service(ReqOut -> RepIn) -> RepOut trait Filter[-ReqIn, +RepOut, +ReqOut, -RepIn] extends ((ReqIn, Service[ReqOut, RepIn]) => Future[RepOut]) 15
  • 16.
    // A filterthat does nothing. def identity[Req, Rep] = new Filter[Req, Rep, Req, Rep] { def apply(req: Req, service: Service[Req, Rep]) = service(req) } val auth = identity[HttpRequest, HttpResponse] 16
  • 17.
  • 18.
    A Type-Safe InputFilter 1 object TurnAIntoB extends Filter[A, Rep, B, Rep] { 2 def apply(req: A, service: Service[B, Rep]): Future[Rep] = 3 service(req.toB) 4 } 5 6 val serviceOfB: Service[B, Rep] = ... 7 val serviceOfA: Service[A, Rep] = TurnAIntoB andThen serviceOfA 18
  • 19.
    A Type-Safe OutputFilter 1 object TurnAIntoB extends Filter[Req, B, Req, A] { 2 def apply(req: Req, service: Service[Req, A]): Future[B] = 3 service(req) map { a => a.toB } 4 } 5 6 val serviceOfA: Service[Req, A] = ... 7 val serviceOfB: Service[Req, B] = TurnAIntoB andThen serviceOfA 19
  • 20.
    Case Study: TimeOutFilter 1 def timeout[Req, Rep](timeout: Duration)(implicit timer: Timer) = 2 new SimpleFilter[Req, Rep] { 3 def apply(req: Req, service: Service[Req, Rep]) = 4 service(req).within(timer, timeout) 5 } 6 7 val handleExceptions = new SimpleFilter[Req, Rep] { 8 def apply(req: Req, service: Service[Req, Rep]) = 9 service(req) handle { 10 case t: TimeOutException => Future.value(defaultRep) 11 } 12 } 13 14 val respond = new Service[Req, Rep] { ... } 15 // We guarantee 3 seconds response time. 16 val backend = handleExceptions andThen 17 timeout(3.seconds) andThen 18 respond 20
  • 21.
    Case Study: OAuth2Filter 1 class OAuth2Filter[U](dataHandler: DataHandler[U]) 2 extends Filter[HttpRequest, HttpResponse, OAuth2Request[U], HttpResponse] 3 with OAuth2 with OAuthErrorHandler { 4 5 def handleError(e: OAuthError) = e.toHttpResponse 6 def apply(req: HttpRequest, service: Service[OAuth2Request[U], HttpResponse]) = 7 authorize(req, dataHandler) flatMap { authInfo => 8 service(OAuth2Request(authInfo, req)) 9 } handle { 10 case e: OAuthError => handleError(e) 11 } 12 } 13 14 val authorize = new OAuth2Filter(...) 15 val respond: Service[OAuth2Request[U], HttpResponse] = ??? 16 val backend: Service[HttpRequest, HttpResponse] = authorize andThen respond 21
  • 22.
    Future is amonad! 22
  • 23.
    Abstraction: Fibonacci Calculator 1 trait FibonacciCalculator { 2 val Zero = BigInt(0) 3 val One = BigInt(1) 4 val Two = BigInt(2) 5 6 def calculate(n: BigInt): Future[BigInt] 7 } 23
  • 24.
    Sequential Composition: map& flatMap 1 trait Future[+A] { 2 def flatMap[B](f: A => Future[B]): Future[B] 3 def map[B](f: A => B): Future[B] 4 } 24
  • 25.
    FlatMap Power 1val ab: Service[A, B] = ??? 2 val bc: Service[B, C] = ??? 3 val cd: Service[C, D] = ??? 4 5 val req: A = ??? 6 val rep: Future[D] = ab(req) flatMap bc flatMap cd 25
  • 26.
    Sequential Composition: map& flatMap 1 object FlatMapFibonacciCalculator extends FibonacciCalculator { 2 def calculate(n: BigInt): Future[BigInt] = 3 if (n == Zero || n == One) Future.value(n) 4 else calculate(n - One) flatMap { a => 5 calculate(n - Two) flatMap { b => Future.value(a + b) } 6 } 7 } 8 9 object MapFibonacciCalculator extends FibonacciCalculator { 10 def calculate(n: BigInt): Future[BigInt] = 11 if (n == Zero || n == One) Future.value(n) 12 else calculate(n - One) map { a => 13 calculate(n - Two) map { b => a + b } 14 } 15 } 26
  • 27.
    Sequential Composition: for-comprehension 1 object ForFibonacciCalculator extends FibonacciCalculator { 2 def calculate(n: BigInt): Future[BigInt] = 3 if (n == Zero || n == One) Future.value(n) 4 else for { 5 a <- calculate(n - One) 6 b <- calculate(n - Two) 7 } yield a + b 8 } 27
  • 28.
    Concurrent Composition: collect& select 1 object Future { 2 def collect[A](fs: Seq[Future[A]]): Future[Seq[A]] 3 def select[A](fs: Seq[Future[A]]): Future[A] 4 } 28
  • 29.
    Concurrent Composition: collect 1 class FanoutFibonacciCalculator( 2 left: FibonacciCalculator, 3 right: FibonacciCalculator) extends FibonacciCalculator { 4 5 def calculate(n: BigInt): Future[BigInt] = 6 if (n == Zero) || n == One) Future.value(n) 7 else { 8 val seq = Seq(left.calculate(n - One), right.calculate(n - Two)) 9 Future.collect(seq) map { _.sum } 10 } 11 } 29
  • 30.
    Concurrent Composition: select 1 class SelectFibonacciCalculator(seq: Seq[FibonacciCalculator]) 2 extends FibonacciCalculator { 3 4 def calculate(n: BigInt): Future[BigInt] = { 5 val futures: Seq[Future[BigInt]] = seq map { _.calculate(n) } 6 Future.select(futures) 7 } 8 } 30
  • 31.
    Futures should be chained asynchronously 31
  • 32.
    Do Not Await // Asynchronous operation. val f = service(req) // Blocking operation. Await.result(f) 32
  • 33.
    Involving Side-Effects //Asynchronous operation. val f = service(req) ! f onSuccess { rep => println("Got the value: " + rep) } onFailure { t => t.printStackTrace() } 33
  • 34.
    Finagle is anon-blocking glue for services that implement different protocols 34
  • 35.
    Finagle is extremelygood at gluing things that work with different speed 35
  • 36.
    References § http://twitter.github.io/finagle/ ! § http://vkostyukov.ru/posts/finagle-your-fibonacci-calculation/ ! § https://github.com/finagle/finch ! § https://github.com/finagle/finagle-oauth2 36
  • 37.
    Stay Finagled! ! And drop your feedbacks to @vkostyukov 37