Thursday, August 14, 2014

Multithreading with Scala and Akka-Actor : PingPong game example

  This small blog post is not only for those who have read/reading cool Scala Cookbook and more specifically chapter about how to use Akka toolkit. Akka with Actors helps to build up highly concurrent, distributed and fault tolerant event-driven application ("we are reactive") on the JVM.

 I'll little modify example which comes from the Scala Cookbook and make new SBT based project out of it to show multi-threading outcome. The build.sbt file:
name := "miko-scala-akka"
version := "1.0"
libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor" % "2.4-SNAPSHOT",
  "com.typesafe.akka" %% "akka-testkit" % "2.4-SNAPSHOT",
  "org.slf4j" % "jcl-over-slf4j" % "1.7.7" ,
  "org.slf4j" % "slf4j-api" % "1.7.7" ,
  "org.slf4j" % "slf4j-log4j12" % "1.7.7",
  "org.apache.logging.log4j" % "log4j" % "2.0" excludeAll(
      ExclusionRule(organization = "com.sun.jdmk"),
      ExclusionRule(organization = "com.sun.jmx"),
      ExclusionRule(organization = "javax.jms")
      ),
  "org.scalatest" % "scalatest_2.11" % "2.2.1" % "test",
  "junit" % "junit" % "4.11" % "test"
)
resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"
  Every Actor from Akka toolkit should send immutable messages (note: we will check it). For such purpose is used binary operator "!" after which the message is passed as an argument.
Ping Actor:
class Pong extends Actor{
  val name: String = "pongActor"
  def receive = {
    case PingMessage =>
      println(" pong")
      sender ! PongMessage
    case StopMessage =>
      println(" pong stopped")
      context.stop(self)
  }
}
Pong Actor:
class Pong extends Actor{
  def receive = {
    case PingMessage =>
      println(" pong")
      sender ! PongMessage
    case StopMessage =>
      println(" pong stopped")
      context.stop(self)
  }
}
our Ping and Pong actors are defined but used messages not. We create 4 case object (case object can be serialized, pattern matching support, default implementation of equals and hashCode ...
case object PingMessage {
  println("This is PingMessage")
}
case object PongMessage {
  println("This is PongMessage")
}
case object StartMessage {
  println("This is StartMessage")
}
case object StopMessage {
  println("This is StopMessage")
}
  Now we have everything ready to create final object PingPongTest:
object PingPongTest{
  private val logger = LoggerFactory.getLogger(getClass)
  def main(args: Array[String]): Unit = {
    logger.debug("---PingPong Game Start---")
    val system = ActorSystem("PingPongSystem")
    val pong = system.actorOf(Props[Pong], name = "pong")
    val ping = system.actorOf(Props(new Ping(pong)), name = "ping")

    // Start the game
    ping ! StartMessage
    logger.debug("---PingPong Game Stop---")
    system.shutdown()
  }
}
  The main purpose of updating the PingPong game is to show how Reactive Application (multi-threading) works . The Simple Logging Facade (SLF4j) Logger is used here to hightlight the simple reactive application flow.
DEBUG: miko.scala.akka.pingpong.PingPongTest$ - ---PingPong Game App Start---
This is StartMessage
DEBUG: miko.scala.akka.pingpong.PingPongTest$ - ---PingPong Game App End---
ping
This is PingMessage
 pong
This is PongMessage
ping
 pong
ping
 pong
ping
 pong
ping
 pong
ping
 pong
ping
 pong
ping
This is StopMessage
ping stopped
 pong stopped
  From the file output is visible how exciting multi-threading environment is. The event-driven distributed system design could more fit to the nature reality of the world around us. 
Enjoy with GiTHub example

No comments: