Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Having fun with Play2, Akka and WebSockets

Having fun with Play2, Akka and WebSockets

Victor Siu-Leung Chan describes how The New York Times CMS team built a reactive messaging system on Play2, Akka and Websocket.

This talk focuses on how the team used Akka and Play2 to pattern the core engine of the system. The approach addresses multiple topics, including subscribe/unsubscribe from either multiple users or multiple tabs, broadcasting with filter and handling keep-alive protocol to keep track of user resources (i.e., locks).

Presented at NE Scala Symposium in March 2014. Video of Victor's talk is on YouTube.

More Decks by The New York Times Developers

Other Decks in Technology

Transcript

  1. @NYTDevs | developers.nytimes.com Play! 2, Akka and WebSockets Having fun

    with Victor Siu-Leung Chan NE Scala Symposium 2014
  2. @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
  3. @NYTDevs | developers.nytimes.com Master Node (Singleton Actor) receive = {

    case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //...
  4. @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 } }
  5. @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
  6. @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]
  7. @NYTDevs | developers.nytimes.com Master Node (Singleton Actor) Yoda Leaf Node

    (Yoda) val Iteratee val Enumerator Yoda receive = { case MSG_SUBSCRIBE => //… case MSG_UNSUBSCRIBE => //...
  8. @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 => //...
  9. @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)
  10. @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
  11. @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
  12. @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) }
  13. @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
  14. @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)
  15. @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
  16. @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!!!
  17. @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!