Slide 1

Slide 1 text

@NYTDevs | developers.nytimes.com Play! 2, Akka and WebSockets Having fun with Victor Siu-Leung Chan NE Scala Symposium 2014

Slide 2

Slide 2 text

@NYTDevs | developers.nytimes.com NYT CMS to deliver news & articles Blackbeard 5 ~ 10 editors per article 300 ~ 400 articles per day High interaction among users Single-page web application

Slide 3

Slide 3 text

@NYTDevs | developers.nytimes.com Scala 2.10.0 Play! 2.1.5 Akka 2.2.0 Backend Framework: SBT 0.12.2

Slide 4

Slide 4 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //...

Slide 5

Slide 5 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //... Singleton object of WebSocket endpoint object MasterNode { /* Get the singleton master actor */ lazy val master: ActorRef = { val masterActor = Akka.system.actorOf(Props[MasterNode], name = "masterNode") masterActor } }

Slide 6

Slide 6 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //... Yoda Leaf Node (Yoda) val Iteratee val Enumerator * Create a child actor node

Slide 7

Slide 7 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //... Yoda Leaf Node (Yoda) val Iteratee val Enumerator Iteratees and Enumerator val in: Iteratee[JsValue, _] = Iteratee.foreach[JsValue] { msg => context.parent ! Msg } val (outEnum, outChannel): (Enumerator[JsValue], Concurrent.Channel[JsValue]) = Concurrent.broadcast[JsValue]

Slide 8

Slide 8 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) Yoda Leaf Node (Yoda) val Iteratee val Enumerator Yoda receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //...

Slide 9

Slide 9 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) Yoda Leaf Node (Yoda) val Iteratee val Enumerator Yoda Darth Vader Leaf Node (Darth Vader) val Iteratee val Enumerator * Create another child actor node receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //...

Slide 10

Slide 10 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) Yoda Leaf Node (Yoda) val Iteratee val Enumerator Yoda Darth Vader Leaf Node (Darth Vader) val Iteratee val Enumerator receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //... BroadCaster If … else … Controller/ External CMS (ActiveMQ)

Slide 11

Slide 11 text

@NYTDevs | developers.nytimes.com Master Node (Singleton Actor) Yoda Leaf Node (Yoda) val Iteratee val Enumerator Yoda Darth Vader Leaf Node (Darth Vader) val Iteratee val Enumerator receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //... BroadCaster If … else … Controller/ External CMS (ActiveMQ) node ! PiosonPill

Slide 12

Slide 12 text

@NYTDevs | developers.nytimes.com Design Pattern Lazy initialization Singleton Chain of responsibility decorator Adapter Cake pattern Self-type annotation Domain Driven Design (DDD) Factory Command Strategy

Slide 13

Slide 13 text

@NYTDevs | developers.nytimes.com Sharp learning curve Result Quick development cycle. Agile User satisfaction J

Slide 14

Slide 14 text

@NYTDevs | developers.nytimes.com Filters for every HTTP request What we’ve learned object AuthFilter extends Filter with Secured { override def apply(next: RequestHeader => Result)(rh: RequestHeader): Result = { if (authRequired(rh)) { checkAuthentication(next)(rh) } else next(rh) }

Slide 15

Slide 15 text

@NYTDevs | developers.nytimes.com Qualify private method, easier to test What we’ve learned package blackbeard.controllers private[controllers] def workflowHelper = { … } //private to the package ========================================= object ArticleControllerSpec extends Specification { //in testing package “private helper function” should { “be accessed” in { workflowHelper

Slide 16

Slide 16 text

@NYTDevs | developers.nytimes.com Define custom write for serializable object What we’ve learned implicit val articleWrites = Json.writes[Article] def articleMinWrites = new Writes[Article] { def writes(a: Article): JsValue = { //get only the core fields …. Json.toJson(article)(articleMinWrites)

Slide 17

Slide 17 text

@NYTDevs | developers.nytimes.com Restful Call over WebSocket message to command What we’ve learned Good for frontend framework Use Play JSON validation API Keep actor logic as simple as possible

Slide 18

Slide 18 text

@NYTDevs | developers.nytimes.com Beware of using Future within Actor receive - sender is not there! What we’ve learned protected def handleQueryMsg: Receive = { case MSG_QUERY(js) => val f = Future {...} f map { result => sender ! MSG_RESULT(result) } // Dead letters!!!

Slide 19

Slide 19 text

@NYTDevs | developers.nytimes.com Using Future, instead of actors (execution context) What we’ve learned implicit val ec: ExecutionContext = ExecutionContext.fromExecutor(Executors.newCachedThreadPool()) Future { …. /* some expensive work */ } //Running in ec!

Slide 20

Slide 20 text

@NYTDevs | developers.nytimes.com Thank you! [email protected] Question? http://open.blogs.nytimes.com/