Hello world with Akka

Let's install Akka. We add it as a dependency to our build.sbt file:

scalaVersion := "2.11.7"

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.4.0"

We can now import Akka as follows:

import akka.actor._

For our first foray into the world of actors, we will build an actor that echoes every message it receives. The code examples for this section are in a directory called chap09/hello_akka in the sample code provided with this book (https://github.com/pbugnion/s4ds):

// EchoActor.scala
import akka.actor._

class EchoActor extends Actor with ActorLogging {
  def receive = {
    case msg:String => 
      Thread.sleep(500)
      log.info(s"Received '$msg'") 
  }
}

Let's pick this example apart, starting with the constructor. Our actor class must extend Actor. We also add ActorLogging, a utility trait that adds the log attribute.

The Echo actor exposes a single method, receive. This is the actor's only way of communicating with the external world. To be useful, all actors must expose a receive method. The receive method is a partial function, typically implemented with multiple case statements. When an actor starts processing a message, it will match it against every case statement until it finds one that matches. It will then execute the corresponding block.

Our echo actor accepts a single type of message, a plain string. When this message gets processed, the actor waits for half a second and then echoes the message to the log file.

Let's instantiate a couple of Echo actors and send them messages:

// HelloAkka.scala

import akka.actor._

object HelloAkka extends App {

  // We need an actor system before we can 
  // instantiate actors
  val system = ActorSystem("HelloActors")

  // instantiate our two actors
  val echo1 = system.actorOf(Props[EchoActor], name="echo1")
  val echo2 = system.actorOf(Props[EchoActor], name="echo2")

  // Send them messages. We do this using the "!" operator
  echo1 ! "hello echo1"
  echo2 ! "hello echo2"
  echo1 ! "bye bye"

  // Give the actors time to process their messages, 
  // then shut the system down to terminate the program
  Thread.sleep(500)
  system.shutdown
}

Running this gives us the following output:

[INFO] [07/19/2015 17:15:23.954] [HelloActor-akka.actor.default-dispatcher-2] [akka://HelloActor/user/echo1] Received 'hello echo1'
[INFO] [07/19/2015 17:15:23.954] [HelloActor-akka.actor.default-dispatcher-3] [akka://HelloActor/user/echo2] Received 'hello echo2'
[INFO] [07/19/2015 17:15:24.955] [HelloActor-akka.actor.default-dispatcher-2] [akka://HelloActor/user/echo1] Received 'bye bye'

Note that the echo1 and echo2 actors are clearly acting concurrently: hello echo1 and hello echo2 are logged at the same time. The second message, passed to echo1, gets processed after the actor has finished processing hello echo1.

There are a few different things to note:

  • To start instantiating actors, we must first create an actor system. There is typically a single actor system per application.
  • The way in which we instantiate actors looks a little strange. Instead of calling the constructor, we create an actor properties object, Props[T]. We then ask the actor system to create an actor with these properties. In fact, we never instantiate actors with new: they are either created by calling the actorOf method in the actor system or a similar method from within another actor (more on this later).

We never call an actor's methods from outside that actor. The only way to interact with the actor is to send messages to it. We do this using the tell operator, !. There is thus no way to mess with an actor's internals from outside that actor (or at least, Akka makes it difficult to mess with an actor's internals).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.171.107