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

Activator and Reactive at Play NYC meetup

Embed Size (px)

DESCRIPTION

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

Citation preview

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