activator and reactive at play nyc meetup

43
Henrik Engstrom Software Engineer @h3nk3 What Constitutes a Reactive Application Reactive Patterns Applied

Upload: henrik-engstroem

Post on 01-Dec-2014

635 views

Category:

Software


4 download

DESCRIPTION

Slides from the presentation given at PlayNYC and GiltTech meetup in New York on 24th of September.

TRANSCRIPT

Page 1: Activator and Reactive at Play NYC meetup

Henrik Engstrom Software Engineer

@h3nk3

What Constitutes a Reactive Application

Reactive Patterns Applied

Page 2: Activator and Reactive at Play NYC meetup

2

Page 3: Activator and Reactive at Play NYC meetup

3

Activator UI!(JavaScript, Knockout, CSS3, black magic…)

Play Application!(Play 2.3.x, Akka 2.3.x, sbt 0.13.x)

sbt Server

websockets

sbt protocol

Async Communication!Websockets!Akka Actors

Other Clients

(Eclipse, Terminal, etc.)

Page 4: Activator and Reactive at Play NYC meetup

DEMO

4

Page 5: Activator and Reactive at Play NYC meetup

Reactive Applications

The Four Reactive Traits

5

http://reactivemanifesto.org/

Page 6: Activator and Reactive at Play NYC meetup

Message-Driven !

The Foundation of being Reactive

Page 7: Activator and Reactive at Play NYC meetup

Akka Actors in 5 minutes or so…

7

Page 8: Activator and Reactive at Play NYC meetup

8

ACTORS

Page 9: Activator and Reactive at Play NYC meetup

9

import akka.actor._ !class GreetingActor extends Actor with ActorLogging { import GreetingActor._ def receive = { case User(name) => log.info(s“Hello there ${name}”) } } !object GreetingActor { case class User(name: String) def props: Props = Props(classOf[GreetingActor]) }

Page 10: Activator and Reactive at Play NYC meetup

10

MAILBOXES

Page 11: Activator and Reactive at Play NYC meetup

11

THREADS

Page 12: Activator and Reactive at Play NYC meetup

12

STATE

Page 13: Activator and Reactive at Play NYC meetup

13

CONTAINERS

Page 14: Activator and Reactive at Play NYC meetup

14

val system = ActorSystem(“MySystem”) val greeter: ActorRef = system.actorOf(GreetingActor.props, “greeter”)

Page 15: Activator and Reactive at Play NYC meetup

15

MESSAGES

Page 16: Activator and Reactive at Play NYC meetup

16

greeter ! GreetingActor.User(“PlayNYC”) // or greeter.tell(GreetingActor.User(“PlayNYC”))

Page 17: Activator and Reactive at Play NYC meetup

17

import akka.actor._ !object Sample extends App { val system = ActorSystem(“MySystem”) val greeter = system.actorOf(GreetingActor.props, “greeter”) greeter ! GreetingActor.User(“PlayNYC”) Thread.sleep(1000) // wait a little before shutting down system.shutdown() } !class GreetingActor extends Actor with ActorLogging { def receive = { case GreetingActor.User(name) => log.info(s“Hello there ${name}”) } } !object GreetingActor { case class User(name: String) def props: Props = Props(classOf[GreetingActor]) }

Page 18: Activator and Reactive at Play NYC meetup

18

he-mbp:sample he$ scalac Sample.scala !he-mbp:sample he$ scala Sample ![INFO] [09/15/2014 16:57:19.879] [MySystem-akka.actor.default-dispatcher-4] [akka://MySystem/user/greeter] Hello there PlayNYC !he-mbp:sample he$

Page 19: Activator and Reactive at Play NYC meetup

Resilient !

Responsive in the Face of Failure

Page 20: Activator and Reactive at Play NYC meetup

20

SUPERVISION

Page 21: Activator and Reactive at Play NYC meetup

21

import akka.actor.OneForOneStrategy import akka.actor.SupervisorStrategy._ import scala.concurrent.duration._ class SupervisorActor extends Actor with ActorLogging { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: SomeDbException => Resume case _: SomeOtherDbException => Restart case _: Exception => Escalate } ! val dbActor = context.actorOf(DbActor.props) def receive = { case op: SomeDbOperation => dbActor forward op } }

Page 22: Activator and Reactive at Play NYC meetup

22

BULKHEAD

Page 23: Activator and Reactive at Play NYC meetup

23

CIRCUIT BREAKER

Page 24: Activator and Reactive at Play NYC meetup

Elastic !

Responsive in the Face of Changing Load

Page 25: Activator and Reactive at Play NYC meetup

2525

Proxy

Play App 1 Play App2 Play App n…

SOME CHALLENGES • Each user has state (location) • Horizontal scaling => !sticky sessions • How do we route to the right node? • Node Crashes • Proxy is SPOF

Page 26: Activator and Reactive at Play NYC meetup

2626

Play App

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Page 27: Activator and Reactive at Play NYC meetup

27

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Shard Coord.

Shard Region

Shard Region

Shard Region

Shard Region

Page 28: Activator and Reactive at Play NYC meetup

28

Supported HTTP commands (Play routes file) !GET / controller.Application.index PUT /create/user/:userId c.Application.createUser(userId: String) POST /update/user/:userId c.Application.updateUser(userId: String)

Page 29: Activator and Reactive at Play NYC meetup

29

package controller object Application extends Controller { val userController = AppGlobal.system.actorOf(UserController.props) ! def index = Action { Ok(“Node is up”) } ! def createUser(userId: String) = Action { userController ! UserController.CreateUser(userId) Ok("new user is created") } ! def updateUser(userId: String) = Action { userController ! UserController.UpdateUser(userId, request.getQueryString(“msg")) Ok("user is updated") } }

Page 30: Activator and Reactive at Play NYC meetup

30

object AppGlobal extends GlobalSettings { private[this] var _system: Option[ActorSystem] = None def system = _system.getOrElse(throw new RuntimeException(“…”)) ! override def onStart(app: Application) = { _system = Some(ActorSystem(“ClusterSystem”)) _system.foreach(createShard(_)) } ! override def onStop(app: Application) = { system.foreach(_.shutdown()) } ! private def createShard(system: ActorSystem) = { ClusterSharding(system).start( typeName = User.shardName, entryProps = Some(User.props), idExtractor = User.idExtractor, shardResolver = User.shardResolver ) } }

Page 31: Activator and Reactive at Play NYC meetup

31

object User { val shardName = "users" def props: Props = Props(classOf[User]) ! trait UserMessage { def userId: String } case class CreateUser(userId: String) extends UserMessage case class UpdateUser(userId: String, text: String) extends UserMessage val idExtractor: ShardRegion.IdExctrator = { case um: UserMessage => (um.userId, um) } val shardResolver: ShardRegion.ShardResolver = { case um: UserMessage => (Math.abs(um.userId.hashCode) % 20).toString } }

Page 32: Activator and Reactive at Play NYC meetup

32

class User extends Actor with ActorLogging { var currentMessage: Option[String] = None def receive = { case CreateUser(userId) => currentMessage = Some(s"User created: ${userId}”) case UpdateUser(userId, text) => log.info(s“User ${userId} now has msg ${text}”) currentMessage = Some(text) } }

Page 33: Activator and Reactive at Play NYC meetup

33

akka { actor.provider = "akka.cluster.ClusterActorRefProvider" remote.nettytcp { port = 0 hostname = "127.0.0.1" } ! remote.log-remote-lifecycle-events = on ! cluster { seed-nodes = [ "akka.tcp://[email protected]:2551", "akka.tcp://[email protected]:2552" ] } ! auto-down-unreachable-after = 30s }

Page 34: Activator and Reactive at Play NYC meetup

3434

Play App

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Akka!Cluster!Node

Page 35: Activator and Reactive at Play NYC meetup

Responsive !

Always Available - Interactive -

(near) Real-Time

Page 36: Activator and Reactive at Play NYC meetup

36

package controllers !import play.api._ import play.api.mvc._ import play.api.libs.json._ import play.api.Play.current import actors.WebSocketActor !object Application extends Controller { def index = Action { Ok(views.html.index("Your new application is ready.")) } ! def socket = WebSocket.acceptWithActor[JsValue, JsValue] { request => out => WebSocketActor.props(out) } }

Page 37: Activator and Reactive at Play NYC meetup

37

object WebSocketActor { def props(out: ActorRef) = Props(new WebSocketActor(out)) case object Again } !class WebSocketActor(out: ActorRef) extends Actor { import WebSocketActor._ var user: Option[String] = None def receive = { case json: JsValue => val name = (json \ "name").as[String] user = Some(name) reply(name) context.system.scheduler.scheduleOnce(3 seconds, self, Again) case Again => user.foreach{reply(_)} } ! def reply(name: String) = { out ! Json.obj("message" -> s"Hello there ${name}") } }

Page 38: Activator and Reactive at Play NYC meetup

38

# routes file GET / controllers.Application.index GET /socket controllers.Application.socket !> var ws = new WebSocket("ws://localhost:9000/socket"); > ws.onmessage = function(msg) { console.log(">", msg); }; > ws.send(JSON.stringify({"name": “PlayNYC"})); !> MessageEvent {ports: Array[0], data: "{"message":"Hello there PlayNYC"}", source: null, lastEventId: "", origin: "ws://localhost:9000"…} !> MessageEvent {ports: Array[0], data: "{"message":"Hello there PlayNYC"}", source: null, lastEventId: "", origin: "ws://localhost:9000"…}

Page 39: Activator and Reactive at Play NYC meetup

39

import play.api.libs.json._ import play.api.mvc.WebSocket.FrameFormatter !implicit val inEventFormat = Json.format[InEvent] implicit val outEventFormat = Json.format[OutEvent] !//Play provides default FrameFormatter for String or JsValue implicit val inEFF = FrameFormatter.jsonFrame[InEvent] implicit val outEFF = FrameFormatter.jsonFrame[OutEvent] !def socket = WebSocket.acceptWithActor[InEvent, OutEvent] { request => out => WebSocketActor.props(out) }

Page 40: Activator and Reactive at Play NYC meetup

4040

CoordActor

TwActor FBActor WActor

Twitter Facebook weather.com

Entry Actor

Request Response

Page 41: Activator and Reactive at Play NYC meetup

41

RESOURCES !Activator - get it now! http://typesafe.com/platform/getstarted !Awesome Example Code by Nilanjan Raychaudhuri https://github.com/nraychaudhuri/scaladays2014/tree/master/play-akka-sharding !Play Websockets https://www.playframework.com/documentation/2.3.x/ScalaWebSockets !Akka Cluster Sharding http://doc.akka.io/docs/akka/2.3.6/contrib/cluster-sharding.html

Page 42: Activator and Reactive at Play NYC meetup

Reactive Applications

The Four Reactive Traits

42

http://reactivemanifesto.org/

Page 43: Activator and Reactive at Play NYC meetup

©Typesafe 2014 – All Rights Reserved All images in this presentation are from www.morguefile.com