Async

React

instead of waiting for better times

Johan Andrén

johan.andren@mejsla.se
@apnylle
In the olden days...
... there was a way to write
web applications

that bound 1 thread per request

oh, wait!
let me fix ...
Most modern web
frameworks
do bind 1 thread per request
do bind 1 thread per request
t1
Request
Thread
pool

t1
ReSponse
What does that thread spend
most of its time doing?
Hint:
Wait
Request

YOur logic

Blocked

yOur logic

ReSponse

WS
Why is this a problem?

• threadpool depletion
• server choked with 5% cpu usage
• unrelated requests affected
Async!
nodejs

All kinds
of Cool Shit
you never heard
about
WUT!?
Let someone invoke our logic
when a resource is available
What is a resource?
• network

• disk

• internal state
Don´t call us
We´ll call you
Our logic

WS
Async
HTTP-client
Our logic
What do we need?

• callback based clients/drivers/libs
• framework support
but doesn’t this lead to...
”Callback Hell”?

1 GMaps.geocode({!
2
address: fromAddress,!
3
callback: function( results, status ) {!
4
if ( status == ...
25
}!
26 });

Not with better abstractions!

• futures / promises
• actors
Future[T]
Empty

Completed

(

Failed )

t
Composition
Future[A]

Future[B]
Map

When A arrives
Apply this A
B transformation
Play action
1 package controllers!
2 !
3 import play.api.mvc._!
4 !
5 object LuckyNumberController extends Controller {!
6...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package controllers!
!
import scala.concurrent.Future!
imp...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

package controllers!
!
import scala.concurrent.Future!
imp...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package controllers!
!
import scala.concurrent.Future!
import...
Future[T]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package controllers!
!
import scala.concurrent.Futu...
Future[T]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package controllers!
!
import scala.concurrent.Futu...
Future[T]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package controllers!
!
import scala.concurrent.Futu...
If there was an exception
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Future[T]

package controllers!
!
i...
Future[T]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import play.api.libs.ws._!
import play.api....
Actors
State
Inbox
Behaviour
• no work - no thread
• react - no waiting
• can have private state
Actor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor.Actor!
!
case object GiveMeNu...
Actor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor.Actor!
!
case object GiveMeNu...
Actor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor.Actor!
!
case object GiveMeNu...
Controller (calling actor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor._!
impor...
Controller (calling actor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor._!
impor...
Controller (calling actor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor._!
impor...
Controller (calling actor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package controllers!
!
import akka.actor._!
impor...
What to look out for

• really heavy computations
• blocking by miss-take
• jdbc :(
I wanna try it!
www.playframework.com
typesafe.com
Qs?
K Thx Bye!
Johan Andrén

johan.andren@mejsla.se
@apnylle
Upcoming SlideShare
Loading in …5
×

Async – react, don't wait

2,902 views
2,708 views

Published on

Slides from my topconf 2013 talk

Published in: Technology, Business
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,902
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
32
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Async – react, don't wait

  1. 1. Async React instead of waiting for better times Johan Andrén johan.andren@mejsla.se @apnylle
  2. 2. In the olden days... ... there was a way to write web applications that bound 1 thread per request oh, wait! let me fix that for me
  3. 3. Most modern web frameworks do bind 1 thread per request
  4. 4. do bind 1 thread per request t1 Request Thread pool t1 ReSponse
  5. 5. What does that thread spend most of its time doing? Hint:
  6. 6. Wait Request YOur logic Blocked yOur logic ReSponse WS
  7. 7. Why is this a problem? • threadpool depletion • server choked with 5% cpu usage • unrelated requests affected
  8. 8. Async! nodejs All kinds of Cool Shit you never heard about
  9. 9. WUT!? Let someone invoke our logic when a resource is available What is a resource? • network • disk • internal state
  10. 10. Don´t call us We´ll call you Our logic WS Async HTTP-client Our logic
  11. 11. What do we need? • callback based clients/drivers/libs • framework support but doesn’t this lead to...
  12. 12. ”Callback Hell”? 1 GMaps.geocode({! 2 address: fromAddress,! 3 callback: function( results, status ) {! 4 if ( status == "OK" ) {! 5 fromLatLng = results[0].geometry.location;! 6 GMaps.geocode({! 7 address: toAddress,! 8 callback: function( results, status ) {! 9 if ( status == "OK" ) {! 10 toLatLng = results[0].geometry.location;! 11 map.getRoutes({! 12 origin: [ fromLatLng.lat(), fromLatLng.lng() ],! 13 destination: [ toLatLng.lat(), toLatLng.lng() ],! 14 travelMode: "driving",! 15 unitSystem: "imperial",! 16 callback: function( e ){! 17 console.log("ANNNND FINALLY here's the directions.. 18 // do something with e! 19 }! 20 });! 21 }! 22 }! 23 });! 24 }!
  13. 13. 25 }! 26 }); Not with better abstractions! • futures / promises • actors
  14. 14. Future[T] Empty Completed ( Failed ) t
  15. 15. Composition Future[A] Future[B] Map When A arrives Apply this A B transformation
  16. 16. Play action 1 package controllers! 2 ! 3 import play.api.mvc._! 4 ! 5 object LuckyNumberController extends Controller {! 6 ! 7 def giveMeLuckyNumber = Action {! 8 ! 9 Ok(views.html.luckyNumber(42))! 10! 11 }! 12 ! 13 }
  17. 17. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action {! ! val fResponse: Future[Response] = ! WS.url("http://lucky-number.api/lucky-number").get! ! ! ! ! ! ! ! ! }! ! } Will start execute here
  18. 18. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action {! ! val fResponse: Future[Response] = ! WS.url("http://lucky-number.api/lucky-number").get! ! ! ! ! ! ! ! ! }! ! } THe future response
  19. 19. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action {! ! val fResponse: Future[Response] = WS.url("http://lucky-number.api/lucky-number").get! ! val fNumber: Future[Int] = fResponse.map { response: Response =>! Integer.parseInt(response.body)! }! ! ! ! ! }! ! } When it arrives: do this Response Int Transformation
  20. 20. Future[T] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action {! ! val fResponse: Future[Response] = WS.url("http://lucky-number.api/lucky-number").get! ! val fNumber: Future[Int] = fResponse.map { response: Response =>! Integer.parseInt(response.body)! }! ! ! ! ! }! ! } (On this Execution context)
  21. 21. Future[T] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action {! ! val fResponse: Future[Response] = WS.url("http://lucky-number.api/lucky-number").get! ! val fNumber: Future[Int] = fResponse.map { response: Response =>! Integer.parseInt(response.body)! }! ! fNumber.map { number =>! Ok(views.html.luckyNumber(number))! }! }! ! } When it arrives: do this Transformation
  22. 22. Future[T] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action.async {! ! val fResponse: Future[Response] = WS.url("http://lucky-number.api/lucky-number").get! ! val fNumber: Future[Int] = fResponse.map { response: Response =>! Integer.parseInt(response.body)! }! ! fNumber.map { number =>! Ok(views.html.luckyNumber(number))! }! }! ! } Play allows us to return a Future[Result]
  23. 23. If there was an exception 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Future[T] package controllers! ! import scala.concurrent.Future! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action.async {! ! val fResponse: Future[Response] = WS.url("http://lucky-number.api/lucky-number").get! ! val fNumber: Future[Int] = fResponse.map { response: Response =>! Integer.parseInt(response.body)! }! ! fNumber.map { number =>! Ok(views.html.luckyNumber(number))! }! }! ! }
  24. 24. Future[T] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import play.api.libs.ws._! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! object LuckyNumberController extends Controller {! ! def giveMeLuckyNumber = Action.async {! for {! response <- WS.url("http://lucky-number.api/lucky-number").get! } yield {! val number = Integer.parseInt(response.body)! Ok(views.html.luckyNumber(number))! }! }! ! }
  25. 25. Actors State Inbox Behaviour
  26. 26. • no work - no thread • react - no waiting • can have private state
  27. 27. Actor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor.Actor! ! case object GiveMeNumber! case class HereYaGo(number: Int)! ! class LuckyNumberGenerator extends Actor {! ! var nextNumber = 42! ! def receive = {! case GiveMeNumber =>! sender ! HereYaGo(nextNumber)! nextNumber += 1! ! }! }
  28. 28. Actor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor.Actor! ! case object GiveMeNumber! case class HereYaGo(number: Int)! ! class LuckyNumberGenerator extends Actor {! ! var nextNumber = 42! ! def receive = {! case GiveMeNumber =>! sender ! HereYaGo(nextNumber)! nextNumber += 1! ! }! } state (mutable)
  29. 29. Actor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor.Actor! ! case object GiveMeNumber! case class HereYaGo(number: Int)! ! class LuckyNumberGenerator extends Actor {! ! var nextNumber = 42! ! def receive = {! case GiveMeNumber =>! sender ! HereYaGo(nextNumber)! nextNumber += 1! ! }! } for each message
  30. 30. Controller (calling actor) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor._! import akka.pattern.ask! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! class LuckyNumberController(numberGenerator: ActorRef) extends Controller {! ! def giveMeLuckyNumber = Action.async {! for {! response <- (numberGenerator ? GiveMeNumber).mapTo[HereYaGo]! } yield {! Ok(views.html.luckyNumber(response.number))! }! }! ! } Di (someone gave it to us)
  31. 31. Controller (calling actor) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor._! import akka.pattern.ask! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! class LuckyNumberController(numberGenerator: ActorRef) extends Controller {! ! def giveMeLuckyNumber = Action.async {! for {! response <- (numberGenerator ? GiveMeNumber).mapTo[HereYaGo]! } yield {! Ok(views.html.luckyNumber(response.number))! }! }! ! } Sends message, gives us Future[Any] (reply)
  32. 32. Controller (calling actor) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor._! import akka.pattern.ask! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! class LuckyNumberController(numberGenerator: ActorRef) extends Controller {! ! def giveMeLuckyNumber = Action.async {! for {! response <- (numberGenerator ? GiveMeNumber).mapTo[HereYaGo]! } yield {! Ok(views.html.luckyNumber(response.number))! }! }! ! } We know what we will get back
  33. 33. Controller (calling actor) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package controllers! ! import akka.actor._! import akka.pattern.ask! import play.api.libs.concurrent.Execution.Implicits.defaultContext! import play.api.mvc._! ! class LuckyNumberController(numberGenerator: ActorRef) extends Controller {! ! def giveMeLuckyNumber = Action.async {! for {! response <- (numberGenerator ? GiveMeNumber).mapTo[HereYaGo]! } yield {! Ok(views.html.luckyNumber(response.number))! }! }! ! } Make a webpage out of that
  34. 34. What to look out for • really heavy computations • blocking by miss-take • jdbc :(
  35. 35. I wanna try it! www.playframework.com typesafe.com
  36. 36. Qs? K Thx Bye! Johan Andrén johan.andren@mejsla.se @apnylle

×