Showing posts with label jvm. Show all posts
Showing posts with label jvm. Show all posts

Tuesday, December 26, 2023

When concurrency bites (yet again!): class initialization deadlocks

Concurrent and parallel programming on JVM platform has never been easy: yes, it is significantly safer and simpler than in most programming languages (thanks to outstanding concurrency support by Java language, standard library and JVM) but still, surprises pop up from time to time.

In today's post we are going to learn how a seemingly innocent implementation may intermittently deadlock during the class initialization under some circumstances. To begin, here is the Options class we are going to work with along the way.

package com.example;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public final class Options {
    public final static Options EMPTY = new Builder().build();
    private final Map<String, String> options;
    
    public Options(final Map<String, String> options) {
        this.options = new HashMap<>(Objects.requireNonNull(options));
    }

    @Override
    public String toString() {
        return "Options=" + options.toString();
    }

    public static class Builder {
        public static final Options EMPTY = new Builder().build();
        private final Map<String, String> options = new HashMap<>();

        public Builder option(final String name, final String value) {
            this.options.put(name, value);
            return this;
        }

        public Options build() {
            return new Options(options);
        }
    }
}

The snippet above implements a variation of the Builder pattern (in this case, for Options class). Although the sample is somewhat made up, the similarities to the existing implementations aren't (for example, please check Parts of Rest High-Level Client not thread-safe out). At a glance, it seems to be no-brainer, the code compiles and runs perfectly fine (the console output serves as a proof in this case).

    public static void main(String[] args) {
        System.out.println("New instance: " + new Options.Builder().build());
        System.out.println("EMPTY Options instance: " + Options.EMPTY);
        System.out.println("EMPTY Options.Builder instance: " + Options.Builder.EMPTY);
    }

Once executed, we should see a few lines printed out.

New instance: Options={}
EMPTY Options instance: Options={}
EMPTY Options.Builder instance: Options={}

The attentive reviewer may spot something fishy about this implementation, specifically related to EMPTY static fields: there is an explicit bidirectional (or better to say, circular) dependency between Options and Options.Builder classes. But JVM is able to handle that, non issue, right? Well, yes and no, and to understand why, let us take a look at the variation of the initialization sequence that is triggered concurrently:

    public static void main(String[] args) {
        try (ExecutorService executor = Executors.newFixedThreadPool(2)) {
            executor.submit(() -> System.out.println("New instance: " + new Options.Builder().build()));
            executor.submit(() -> System.out.println("EMPTY Options instance: " + Options.EMPTY));
        }
    }

Surprisingly (or not?), the execution of this code intermittently hangs the JVM. If we look into the thread dump, the reason becomes very clear (thanks to JDK-8288064: Class initialization locking, the output has been redacted a bit to highlight the clues).

"pool-1-thread-1" #29 [8432] prio=5 os_prio=0 cpu=0.00ms elapsed=499.54s allocated=7800B defined_classes=1 tid=0x000002609f22b680 nid=8432 waiting on condition  [0x000000be184fe000]
   java.lang.Thread.State: RUNNABLE
	at com.example.Options$Builder.build(Options.java:35)
	- waiting on the Class initialization monitor for com.example.Options
	at com.example.Options$Builder.<clinit>(Options.java:26)
    ...

"pool-1-thread-2" #30 [19688] prio=5 os_prio=0 cpu=0.00ms elapsed=499.54s allocated=5184B defined_classes=1 tid=0x000002609f233e40 nid=19688 waiting on condition  [0x000000be185fe000]
   java.lang.Thread.State: RUNNABLE
	at com.example.Options.<clinit>(Options.java:9)
	- waiting on the Class initialization monitor for com.example.Options$Builder
    ...

The Options and Options.Builder classes deadlock during initialization (and indeed, Options needs Options.Builder to initialize EMPTY static field however Options.Builder needs Options to initialize own EMPTY static field). The JLS (Java Language Specification) is very clear on that (but how many of us have read the specification anyway?):

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface; for example, a variable initializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure. - 12.4.2. Detailed Initialization Procedure

This is by no means a new issue that could be solved by restructuring the code, it has been known for years (JDK-4891511: Deadlock in class initialization specification, JLS 2nd ed. 12.4.2) but it still bites and not easy to troubleshoot (JDK-8059913: Deadlock finder is unable to find deadlocks caused by <clinit>). Luckily, JVM diagnostics is getting better and upcoming JDK-22 release will bring yet another improvement as part of JDK-8316229: Enhance class initialization logging, it should definitely help to debug apparent class initialization deadlocks (when JVM has class+init debug logging enabled using -Xlog:class+init=debug command line option).

...
[0.089s][debug][class,init] Thread "pool-1-thread-1" is initializing com.example.Options$Builder
[0.089s][debug][class,init] Thread "pool-1-thread-2" is initializing com.example.Options
[0.089s][info ][class,init] 511 Initializing 'com/example/Options$Builder' (0x000002b9dd001000) by thread "pool-1-thread-1"
[0.089s][info ][class,init] 512 Initializing 'com/example/Options' (0x000002b9dd001218) by thread "pool-1-thread-2"
[0.089s][debug][class,init] Thread "pool-1-thread-1" recursively initializing com.example.Options$Builder
[0.089s][debug][class,init] Thread "pool-1-thread-2" waiting for initialization of com.example.Options$Builder by thread "pool-1-thread-1"
[0.089s][debug][class,init] Thread "pool-1-thread-1" waiting for initialization of com.example.Options by thread "pool-1-thread-2"
...

Undoubtedly, JVM is very sophisticated piece of technology and each release (which is happening every six months these days) brings more features, bugfixes and improvements. Despite getting smarter, JVM still requires developers to be aware of its limitations and think about the code they write (would co-pilots and LLMs help with that is yet to be seen).

I πŸ‡ΊπŸ‡¦ stand πŸ‡ΊπŸ‡¦ with πŸ‡ΊπŸ‡¦ Ukraine.

Saturday, May 28, 2022

The lost art of learning ... (a new programming language)

I remember the time, 20 years ago, when as a junior software developer I was driven by constant, non-stoppable desire to learn new things: new features, techniques, frameworks, architectures, styles, practices, ... and surely, new programming languages. This curiosity, hunger to learn, drove me to consume as many books as possible and to hunt around the clock for the scanty online publications available at that time.

Year after year, the accumulated knowledge backed by invaluable experience led me to settle on proven and battle-tested (in production) choices, which have worked, work these days and I am sure will work in the future. For me, the foundation was set in Java (later Scala as well) and JVM platform in general. This is where my expertise lays in, but don't get me wrong, I still try to read a lot, balancing on the edge between books and enormous amount of the blog posts, articles, talks and podcast. How many programming languages I was able to master for the last, let say, 10 years? If we count the JVM ecosystem only, Scala and Groovy would make the list, but otherwise - none, zero, 0. The pace of learning on this front has slowed for me, significantly ...

Why is that? Did I get burned out? Nope (thanks God). Fed up by development? Nope, hopefully never. Opionated? Yes, certainly. Older? Definitely. Less curious? Not really. To be fair, there are so many things going on in the JVM ecosystem, so many projects are being developed by the community, it has become increasingly difficult to find the time for something else! And frankly, why bother if you could do Java for the next 20 years without any fear of it disappearing or becoming irrelevant.

JVM is amazing platform but its fundamental principles heavily impact certain design aspects of any programming language built on top of it. It is good and bad (everything is a trade-off), but with the time, you as a developer get used to it, questioning if anything else makes sense. As many others, I ended up in the bubble which has to be blown up. How? I decided to learn Rust, and go way beyond the basics.

But no worries, I do not intend to sell you Rust but rather share an alarming discovery: the lost art of learning a new programming language. It all started as usual, crunching through the blogs, people's and companies' experiences and finally getting the book, Programming Rust: Fast, Safe Systems Development (really good one but the official The Rust Programming Language is equally awesome). A few months (!) later, I was done reading, feeling ready for delivering cool, production-ready Rust applications, or so I thought ... The truth - I was far, very far from it ... and those are the things I did wrong.

  • Rust is concise (at least, to my taste), modern and powerful, but it is not a simple language. If some language aspects are not clear, do not skip over but try to understand them. If book is not doing sufficiently good job at it, look around till you get them, otherwise you risk to miss even more. I did not do that (overly confident that nothing could be harder than learning functional Scala) and at some point I was somewhat lost.

  • In the same vein, Rust has unique perspective on many things, including concurrency and memory management, and investing the time to understand what those are is a must (the Java/JVM background is not very helpful here). Essentially, you have to "unlearn" in order to grasp certain new concepts, this is not easy and confuses the brain.

  • Stay very focused and methodical, try to read at least few pages **every day**. Yes, we are all super busy, always distracted, have families and started to travel again, ... yada yada yada. Also, Programming Rust: Fast, Safe Systems Development is not a slim book: ~800 pages! Irregular, long breaks in reading were killing my progress.

  • Practice, practice and practice. If you have some pet projects in mind, this is great, if not - just come up with anything ad-hoc but try to use the things you have just read about. Learning the "theory" is great, but mastering the programming language is all about using it every day to solve problems. I screwed there epically by following "bed time story" style ...

  • Learn the coding practices and patterns by looking into the language's ecosystem, in this regard a curated list of Rust code and resources is super useful.

  • Subscribe to newsletters to stay up to date and be aware what is going on in the core development and in the community. In case of Rust, the This Week in Rust turned out to be invaluable.

  • Watch talks and presentations, luckily most of the conferences do publish all their videos online these days. I stumbled upon the official Rust YouTube channel and since then follow it closely.

Learning new programming language is rewarding experience, in particular when it happens to be Rust, a most beloved programming language for the last six years. But not only because of that, Rust is perfect fit for a system programming, something Java/JVM is inherently not suited very well (yes, it is better now with JEP 330: Launch Single-File Source-Code Programs, jbang and GraalVM native images but still far from being perfect for a task). From the other side, it is quite challenging when the programming language you are learning is not part of your day-to-day job.

As of this moment, I am not sure if Rust ever becomes my primary programming language but one thing I do know: I think every passionate software developer should strive to learn at least one new programming language every 1-2 years (we have so many good ones). It is amazing mental exercice and I used to follow this advice back in the days but lost the sight of it along the journey. I really should have not.

Happy learning and peace to everyone!

Saturday, February 28, 2015

A fresh look on accessing database on JVM platform: Slick from Typesafe

In today's post we are going to open our mind, step away from traditional Java EE / Java SE JPA-based stack (which I think is great) and take a refreshing look on how to access database in your Java applications using the new kid on the block: Slick 2.1 from Typesafe. So if JPA is so great, why bother? Well, sometimes you need to do very simple things and there is no need to bring the complete, well modeled persistence layer for that. In here Slick shines.

In the essence, Slick is database access library, not an ORM. Though it is written in Scala, the examples we are going to look at do not require any particular knowledge of this excellent language (although, it is just Scala that made Slick possible to exist). Our relational database schema will have only two tables, customers and addresses, linked by one-to-many relationships. For simplicity, H2 has been picked as an in-memory database engine.

The first question which comes up is defining database tables (schema) and, naturally, database specific DDLs are the standard way of doing that. Can we do something about it and try another approach? If you are using Slick 2.1, the answer is yes, absolutely. Let us just describe our tables as Scala classes:

// The 'customers' relation table definition
class Customers( tag: Tag ) extends Table[ Customer ]( tag, "customers" ) {
  def id = column[ Int ]( "id", O.PrimaryKey, O.AutoInc )

  def email = column[ String ]( "email", O.Length( 512, true ), O.NotNull )
  def firstName = column[ String ]( "first_name", O.Length( 256, true ), O.Nullable )
  def lastName = column[ String ]( "last_name", O.Length( 256, true ), O.Nullable )

  // Unique index for customer's email
  def emailIndex = index( "idx_email", email, unique = true )
}

Very easy and straightforward, resembling a lot typical CREATE TABLE construct. The addresses table is going to be defined the same way and reference users table by foreign key.

// The 'customers' relation table definition
class Addresses( tag: Tag ) extends Table[ Address ]( tag, "addresses" ) {
  def id = column[ Int ]( "id", O.PrimaryKey, O.AutoInc )

  def street = column[ String ]( "street", O.Length( 100, true ), O.NotNull )
  def city = column[ String ]( "city", O.Length( 50, true ), O.NotNull )
  def country = column[ String ]( "country", O.Length( 50, true ), O.NotNull )

  // Foreign key to 'customers' table
  def customerId = column[Int]( "customer_id", O.NotNull )
  def customer = foreignKey( "customer_fk", customerId, Customers )( _.id )
}

Great, leaving off some details, that is it: we have defined two database tables in pure Scala. But details are important and we are going to look closely on following two declarations: Table[ Customer ] and Table[ Address ]. Essentially, each table could be represented as a tuple with as many elements as column it has defined. For example, customers is a tuple of (Int, String, String, String), while addresses table is a tuple of (Int, String, String, String, Int). Tuples in Scala are great but they are not very convenient to work with. Luckily, Slick allows to use case classes instead of tuples by providing so called Lifted Embedding technique. Here are our Customer and Address case classes:

case class Customer( id: Option[Int] = None, email: String, 
  firstName: Option[ String ] = None, lastName: Option[ String ] = None)

case class Address( id: Option[Int] = None,  street: String, city: String, 
  country: String, customer: Customer )

The last but not least question is how Slick is going to convert from tuples to case classes and vice-versa? It would be awesome to have such conversion out-of-the box but at this stage Slick needs a bit of help. Using Slick terminology, we are going to shape * table projection (which corresponds to SELECT * FROM ... SQL construct). Let see how it looks like for customers:

// Converts from Customer domain instance to table model and vice-versa
def * = ( id.?, email, firstName.?, lastName.? ).shaped <> ( 
  Customer.tupled, Customer.unapply )

For addresses table, shaping looks a little bit more verbose due to the fact that Slick does not have a way to refer to Customer case class instance by foreign key. Still, it is pretty straightforward, we just construct temporary Customer from its identifier.

// Converts from Customer domain instance to table model and vice-versa
def * = ( id.?, street, city, country, customerId ).shaped <> ( 
  tuple => {
    Address.apply(
      id = tuple._1,
      street = tuple._2,
      city = tuple._3,
      country = tuple._4,
      customer = Customer( Some( tuple._5 ), "" )
    )
  }, {
    (address: Address) =>
      Some { (
        address.id,
        address.street,
        address.city,
        address.country,
        address.customer.id getOrElse 0 
      )
    }
  }
)

Now, when all details have been explained, how can we materialize our Scala table definitions into the real database tables? Thankfully to Slick, it is a easy as that:

implicit lazy val DB = Database.forURL( "jdbc:h2:mem:test", driver = "org.h2.Driver" )
  
DB withSession { implicit session =>
  ( Customers.ddl ++ Addresses.ddl ).create
}

Slick has many ways to query and update data in database. The most beautiful and powerful one is just using pure functional constructs of the Scala language. The easiest way of doing that is by defining companion object and implement typical CRUD operations in it. For example, here is the method which inserts new customer record into customers table:

object Customers extends TableQuery[ Customers ]( new Customers( _ ) ) {
  def create( customer: Customer )( implicit db: Database ): Customer = 
    db.withSession { implicit session =>
      val id = this.autoIncrement.insert( customer )
      customer.copy( id = Some( id ) )
    } 
}

And it could be used like this:

Customers.create( Customer( None, "[email protected]",  Some( "Tom" ), Some( "Tommyknocker" ) ) )
Customers.create( Customer( None, "[email protected]",  Some( "Bob" ), Some( "Bobbyknocker" ) ) )

Similarly, the family of find functions could be implemented using regular Scala for comprehension:

def findByEmail( email: String )( implicit db: Database ) : Option[ Customer ] = 
  db.withSession { implicit session =>
    ( for { customer <- this if ( customer.email === email.toLowerCase ) } 
      yield customer ) firstOption
  }
   
def findAll( implicit db: Database ): Seq[ Customer ] = 
  db.withSession { implicit session =>      
    ( for { customer <- this } yield customer ) list
  }

And here are usage examples:

val customers = Customers.findAll
val customer = Customers.findByEmail( "[email protected]" )

Updates and deletes are a bit different though very simple as well, let us take a look on those:

def update( customer: Customer )( implicit db: Database ): Boolean = 
  db.withSession { implicit session =>
    val query = for { c <- this if ( c.id === customer.id ) } 
      yield (c.email, c.firstName.?, c.lastName.?)
    query.update(customer.email, customer.firstName, customer.lastName) > 0
  }
  
def remove( customer: Customer )( implicit db: Database ) : Boolean = 
  db.withSession { implicit session =>
    ( for { c <- this if ( c.id === customer.id ) } yield c ).delete > 0
  }

Let us see those two methods in action:

Customers.findByEmail( "[email protected]" ) map { customer =>
  Customers.update( customer.copy( firstName = Some( "Tommy" ) ) )
  Customers.remove( customer )
}

Looks very neat. I am personally still learning Slick however I am pretty excited about it. It helps me to have things done much faster, enjoying the beauty of Scala language and functional programming. No doubts, the upcoming version 3.0 is going to bring even more interesting features, I am looking forward to it.

This post is just an introduction into world of Slick, a lot of implementation details and use cases have been left aside to keep it short and simple. However Slick's documentation is pretty good and please do not hesitate to consult it.

The complete project is available on GitHub.

Monday, May 27, 2013

Real-time charts with Play Framework and Scala: extreme productivity on JVM for web

Being a hardcore back-end developer, whenever I am thinking about building web application with some UI on JVM platform, I feel scared. And there are reasons for that: having experience with JSF, Liferay, Grails, ... I don't want to go this road anymore. But if a need comes, is there a choice, really? I found one which I think is awesome: Play Framework.

Built on top of JVM, Play Framework allows to create web applications using Java or Scala with literally no efforts. The valuable and distinguishing differences it provides: static compilation (even for page templates), easy to start with, and concise (more about it here).

To demonstrate how amazing Play Framework is, I would like to share my experience with developing simple web application. Let's assume we have couple of hosts and we would like to watch CPU usage on each one in real-time (on a chart). When one hears "real-time", it may mean different things but in context of our application it means: using WebSockets to push data from server to client. Though Play Framework supports pure Java API, I will use some Scala instead as it makes code very compact and clear.

Let's get started! After downloading Play Framework (the latest version on the moment of writing was 2.1.1), let's create our app by typing

play new play-websockets-example
and selecting Scala as a primary language. No wonders here: it's a pretty standard way nowadays, right?

Having our application ready, next step would be to create some starting web page. Play Framework uses own type safe template engine based on Scala, it has a couple of extremely simple rules and is very easy to get started with. Here is an example of views/dashboard.scala.html:

@(title: String, hosts: List[Host])

<!DOCTYPE html>
<html>
  <head>
    <title>@title</title>
    <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
    <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
    <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript">
    <script src="@routes.Assets.at("javascripts/highcharts.js")" type="text/javascript">
  </head>
    
  <body>
    <div id="hosts">
      <ul class="hosts">
        @hosts.map { host =>
        <li>               
          <a href="#" onclick="javascript:show( '@host.id' )"><b>@host.name</b></a>
        </li>
        }
      </ul>
    </div>
  
    <div id="content">
    </div>
  </body>
</html>

<script type="text/javascript">
function show( hostid ) {
  $("#content").load( "/host/" + hostid,
    function( response, status, xhr ) {
      if (status == "error") {
        $("#content").html( "Sorry but there was an error:" + xhr.status + " " + xhr.statusText);
      }
    }
  )
}
</script>

Aside from coupe of interesting constructs (which are very well described here), it looks pretty like regular HTML with a bit of JavaScript. The result of this web page is a simple list of hosts in the browser. Whenever user clicks on a particular host, another view will be fetched from the server (using old buddy AJAX) and displayed on right side from the host. Here is the second (and the last) template, views/host.scala.html:

@(host: Host)( implicit request: RequestHeader )

<div id="content">
  <div id="chart">
  <script type="text/javascript">
    var charts = []   
    charts[ '@host.id' ] = new Highcharts.Chart({                 
      chart: {
        renderTo: 'chart',
        defaultSeriesType: 'spline'            
      },           
      xAxis: {
        type: 'datetime'
      },   
      series: [{
        name: "CPU",
        data: []
      }]
    }); 
  </script>
</div>

<script type="text/javascript">
var socket = new WebSocket("@routes.Application.stats( host.id ).webSocketURL()")
socket.onmessage = function( event ) { 
  var datapoint = jQuery.parseJSON( event.data );
  var chart = charts[ '@host.id' ]
  
  chart.series[ 0 ].addPoint({
    x: datapoint.cpu.timestamp,
    y: datapoint.cpu.load
  }, true, chart.series[ 0 ].data.length >= 50 );
}
</script>

It's looks rather as a fragment, not a complete HTML page, which has only a chart and opens the WebSockets connection with a listener. With an enormous help of Highcharts and jQuery, JavaScript programming hasn't ever been so easy for back-end developers as it's now. At this moment, the UI part is completely done. Let's move on to back-end side.

Firstly, let's define the routing table which includes only three URLs and by default is located at conf/routes:

GET     /                           controllers.Application.index
GET     /host/:id                   controllers.Application.host( id: String )
GET     /stats/:id                  controllers.Application.stats( id: String )

Having views and routes defined, it's time to fill up the last and most interesting part, the controllers which glue all parts together (actually, only one controller, controllers/Application.scala). Here is a snippet which maps index action to the view templated by views/dashboard.scala.html, it's as easy as that:

def index = Action {
  Ok( views.html.dashboard( "Dashboard", Hosts.hosts() ) )
}

The interpretation of this action may sound like that: return successful response code and render template views/dashboard.scala.html with two parameters, title and hosts, as response body. The action to handle /host/:id looks much the same:

def host( id: String ) = Action { implicit request =>
  Hosts.hosts.find( _.id == id ) match {
    case Some( host ) => Ok( views.html.host( host ) )
    case None => NoContent
  }    
}

And here is a Hosts object defined in models/Hosts.scala. For simplicity, the list of hosts is hard-coded:

package models

case class Host( id: String, name: String )

object Hosts {  
  def hosts(): List[ Host ] = {
    return List( new Host( "h1", "Host 1" ), new Host( "h2", "Host 2" ) )
  } 
}

The boring part is over, let's move on to the last but not least implementation: server push of host's CPU statistics using WebSockets. As you can see, the /stats/:id URL is already mapped to controller action so let's take a look on its implementation:

def stats( id: String ) = WebSocket.async[JsValue] { request =>
  Hosts.hosts.find( _.id == id ) match {
    case Some( host ) => Statistics.attach( host )
    case None => {
      val enumerator = Enumerator
        .generateM[JsValue]( Promise.timeout( None, 1.second ) )
        .andThen( Enumerator.eof )
      Promise.pure( ( Iteratee.ignore[JsValue], enumerator ) )
    }
  }
}

Not too much code here but in case you are curious about WebSockets in Play Framework please follow this link. This couple of lines may look a bit weird at first but once you read the documentation and understand basic design principles behind Play Framework, it will look much more familiar and friendly. The Statistics object is the one who does the real job, let's take a look on the code:

package models

import scala.concurrent.Future
import scala.concurrent.duration.DurationInt

import akka.actor.ActorRef
import akka.actor.Props
import akka.pattern.ask
import akka.util.Timeout
import play.api.Play.current
import play.api.libs.concurrent.Akka
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.libs.iteratee.Enumerator
import play.api.libs.iteratee.Iteratee
import play.api.libs.json.JsValue

case class Refresh()
case class Connect( host: Host )
case class Connected( enumerator: Enumerator[ JsValue ] )

object Statistics {
  implicit val timeout = Timeout( 5 second )
  var actors: Map[ String, ActorRef ] = Map()
  
  def actor( id: String ) = actors.synchronized {
    actors.find( _._1 == id ).map( _._2 ) match {
      case Some( actor ) => actor      
      case None => {
        val actor = Akka.system.actorOf( Props( new StatisticsActor(id) ), name = s"host-$id" )   
        Akka.system.scheduler.schedule( 0.seconds, 3.second, actor, Refresh )
        actors += ( id -> actor )
        actor
      }
    }
  }
 
  def attach( host: Host ): Future[ ( Iteratee[ JsValue, _ ], Enumerator[ JsValue ] ) ] = {
    ( actor( host.id ) ? Connect( host ) ).map {      
      case Connected( enumerator ) => ( Iteratee.ignore[JsValue], enumerator )
    }
  }
}

As always, thanks to Scala conciseness, not too much code but a lot of things are going on. As we may have hundreds of hosts, it would be reasonable to dedicate to each host own worker (not a thread) or, more precisely, own actor. For that, we will use another amazing library called Akka. The code snippet above just creates an actor for the host or uses existing one from the registry of the already created actors. Please note that the implementation is quite simplified and leaves off important details. The thoughts in right direction would be using supervisors and other advanced concepts instead of synchronized block. Also worth mentioning that we would like to make our actor a scheduled task: we ask actor system to send the actor a message Refresh every 3 seconds. That means that the charts will be updated with new values every three seconds as well.

So, when actor for a host is created, we send him a message Connect notifying that a new connection is being established. When response message Connected is received, we return from the method and at this point connection over WebSockets is about to be established. Please note that we intentionally ignore any input from the client by using Iteratee.ignore[JsValue].

And here is the StatisticsActor implementation:

package models

import java.util.Date

import scala.util.Random

import akka.actor.Actor
import play.api.libs.iteratee.Concurrent
import play.api.libs.json.JsNumber
import play.api.libs.json.JsObject
import play.api.libs.json.JsString
import play.api.libs.json.JsValue

class StatisticsActor( hostid: String ) extends Actor {
  val ( enumerator, channel ) = Concurrent.broadcast[JsValue]
  
  def receive = {
    case Connect( host ) => sender ! Connected( enumerator )       
    case Refresh => broadcast( new Date().getTime(), hostid )
  }
  
  def broadcast( timestamp: Long, id: String ) {
    val msg = JsObject( 
      Seq( 
        "id" -> JsString( id ),
        "cpu" -> JsObject( 
          Seq( 
            ( "timestamp" -> JsNumber( timestamp ) ), 
            ( "load" -> JsNumber( Random.nextInt( 100 ) ) ) 
          ) 
        )
      )
    )
     
    channel.push( msg )
  }
}

The CPU statistics is randomly generated and the actor just broadcasts it every 3 seconds as simple JSON object. On the client side, the JavaScript code parses this JSON and updates the chart. Here is how it looks like for two hosts, Host 1 and Host 2 in Mozilla Firefox:

To finish up, I am personally very excited with what I've done so far with Play Framework. It took just couple of hours to get started and another couple of hours to make things work as expected. The errors reporting and feedback cycle from running application are absolutely terrific, thanks a lot to Play Framework guys and the community around it. There are still a lot of things to learn for me but it worth doing it.

Please find the complete source code on GitHub.