Recent Posts
Archives

PostHeaderIcon [DevoxxFR2013] Soon, in a Galaxy Not So Far Away: Real-Time Web with Play 2, Akka, and Spaceships

Lecturer

Mathieu Ancelin is a software engineer at SERLI, specializing in Java EE technologies with a particular focus on component frameworks. He contributes to open-source projects such as GlassFish, JOnAS, and leads initiatives like CDI-OSGi and Play CDI. A member of the JSR 346 expert group for CDI 1.1, Ancelin regularly teaches at the University of La Rochelle and Poitiers, and speaks at conferences including JavaOne and Solutions Linux. He is active in the Poitou-Charentes JUG and can be followed on Twitter as @TrevorReznik.

Abstract

Mathieu Ancelin demystifies Play 2’s real-time capabilities, answering the perennial question: “WTF are Iteratees?” Through live demonstrations of two playful applications—a multiplayer spaceship battle and a real-time roulette game—he showcases how Play 2 leverages Iteratees, Akka actors, Server-Sent Events (SSE), WebSockets, HTML5 Canvas, and even webcam input to build responsive, interactive web experiences. The session explores how these APIs integrate seamlessly with Java and Scala, enabling developers to create low-latency, event-driven systems using their preferred language. Beyond the fun, Ancelin analyzes architectural patterns for scalability, backpressure handling, and state management in real-time web applications.

Demystifying Iteratees: Functional Streams for Non-Blocking I/O

Ancelin begins by addressing the confusion surrounding Iteratees, a functional reactive programming abstraction in Play 2. Unlike traditional imperative streams, Iteratees separate data production, processing, and consumption, enabling composable, backpressure-aware pipelines.

val enumeratee: Enumeratee[Array[Byte], String] = Enumeratee.map[Array[Byte]].apply[String] { bytes =>
  new String(bytes, "UTF-8")
}

This allows safe handling of chunked HTTP input without blocking threads. When combined with Enumerators (producers) and Enumeratees (transformers), they form robust data flows:

val socket: WebSocket[JsValue, JsValue] = WebSocket.using[JsValue] { request =>
  val in = Iteratee.foreach[JsValue](msg => actor ! msg).map(_ => actor ! PoisonPill)
  val out = Enumerator.fromCallback1(_ => futurePromise.future)
  (in, out)
}

Ancelin demonstrates how this pattern prevents memory leaks and thread exhaustion under load.

Akka Actors: Coordinating Game State and Player Actions

The spaceship game uses Akka actors to manage shared game state. A central GameActor maintains positions, velocities, and collisions:

class GameActor extends Actor {
  var players = Map.empty[String, Player]
  val ticker = context.system.scheduler.schedule(0.millis, 16.millis, self, Tick)

  def receive = {
    case Join(id, out) => players += (id -> Player(out))
    case Input(id, thrust, rotate) => players(id).update(thrust, rotate)
    case Tick => broadcastState()
  }
}

Each client connects via WebSocket, sending input events and receiving rendered frames. The actor model ensures thread-safe updates and natural distribution.

Real-Time Rendering with Canvas and Webcam Integration

The game renders on HTML5 Canvas using client-side JavaScript. Server pushes state via SSE or WebSocket; client interpolates between ticks for smooth 60 FPS animation.

A bonus feature uses getUserMedia() to capture webcam input, mapping head tilt to ship rotation—an engaging demo of sensor fusion in the browser.

navigator.getUserMedia({ video: true }, stream => {
  video.src = URL.createObjectURL(stream);
  tracker.on('track', event => sendRotation(event.data.angle));
});

Play Roulette: SSE for Unidirectional Live Updates

The second demo, Play Roulette, uses Server-Sent Events to broadcast spin results to all connected clients:

def live = Action {
  Ok.chunked(results via EventSource()).as("text/event-stream")
}

Clients subscribe with:

const es = new EventSource('/live');
es.onmessage = e => updateWheel(JSON.parse(e.data));

This pattern excels for broadcast scenarios—news feeds, dashboards, live sports.

Language Interoperability: Java and Scala Working Together

Ancelin emphasizes Play 2’s dual-language support. Java developers use the same APIs via wrappers:

public static WebSocket<JsonNode> socket() {
    return WebSocket.withActor(GameActor::props);
}

This lowers the barrier for Java teams adopting reactive patterns.

Architecture Analysis: Scalability, Fault Tolerance, and Deployment

The system scales horizontally using Akka clustering. Game instances partition by room; a load balancer routes WebSocket upgrades. Failure recovery leverages supervisor strategies.

Deployment uses Play’s dist task to generate start scripts. For production, Ancelin recommends Typesafe ConductR or Docker with health checks.

Implications for Modern Web Applications

Play 2’s real-time stack enables:
Low-latency UX without polling
Efficient resource use via non-blocking I/O
Graceful degradation under load
Cross-language development in polyglot teams

From games to trading platforms, the patterns apply broadly.

Links:

Leave a Reply