Typesafe Activator

Hello Akka!

Hello Akka!

Typesafe
Source
July 25, 2014
basics akka java scala starter

Akka is a toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven apps. This simple application will get you started building Actor based systems in Java and Scala. This app uses Akka 2.2, Java 6, Scala 2.10, JUnit, and ScalaTest.

How to get "Hello Akka!" on your computer

There are several ways to get this template.

Option 1: Choose hello-akka in the Typesafe Activator UI.

Already have Typesafe Activator (get it here)? Launch the UI then search for hello-akka in the list of templates.

Option 2: Download the hello-akka project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for hello-akka.

  1. Download the Template Bundle for "Hello Akka!"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Typesafe Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\hello-akka> activator ui 
    This will start Typesafe Activator and open this template in your browser.

Option 3: Create a hello-akka project from the command line

If you have Typesafe Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME hello-akka on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/typesafehub/activator-hello-akka#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

You've just created a simple Akka application! Now lets explore the code and make some changes.

In short, Akka is a toolkit and runtime for building highly concurrent, distributed, and fault-tolerant event-driven applications on the JVM. Akka can be used with both Java and Scala. One of the most powerful features of Akka is its Actor Model of concurrency, which you will learn more about in this tutorial.

Akka can be used from either Java or Scala and this tutorial has both Java and Scala sample code.

Source code

The java directory contains the Java source code HelloAkkaJava.java and the scala directory contains the Scala source code HelloAkkaScala.scala.

The sample in this tutorial is pretty simple; it consists of a Greeter Actor who holds onto the latest defined greeting string and can respond to two actions; set a new greeting string and return the latest greeting string.

Next let's get started.

Define our Messages

An Actor does not have a public API in terms of methods that you can invoke. Instead its public API is defined through messages that the actor handles. Messages can be of arbitrary type (any subtype of Object in Java or Any in Scala). This means that we can send boxed primitive values (such as String, Integer, Boolean etc.) as messages or plain data structures like arrays and collection types. However, since the messages are the Actor's public API, you should define messages with good names and rich semantic and domain specific meaning, even if it's just wrapping your data type. This will make it easier to use, understand and debug actor-based systems.

Now we want to define three different messages;

  • WhoToGreet redefines the new greeting
  • Greet asks the Actor for latest greeting
  • Greeting returns the latest greeting

Let's start by defining the messages in Java (we are putting them inside an outer HelloAkkaJava class, containing our full sample). It is very important that the messages we create are immutable (meaning that they cannot be changed), if not we run the risk of accidentally sharing state between two different Actors which will violate the Actor Model. In this sample we will not use any remoting, but it is a good practice to always mark your messages as Serializable since then you will not run in to any runtime issues if you decide to scale out (on to multiple nodes) with Akka but forget to go back and reimplement your messages.


// Java code

public static class Greet implements Serializable {}

public static class WhoToGreet implements Serializable {
    public final String who;
    public WhoToGreet(String who) {
        this.who = who;
    }
}

public static class Greeting implements Serializable {
    public final String message;
    public Greeting(String message) {
        this.message = message;
    }
}
        

This is the way we would define the messages in Scala. In Scala case classes and case objects make excellent messages since they are immutable and have support for pattern matching, something we will take advantage of in the Actor when matching on the messages it has received. Another advantage case classes has is that they are marked as serializable by default.


// Scala code

case object Greet
case class WhoToGreet(who: String)
case class Greeting(message: String)
        

Define our Actor

The Actor is the unit of execution in Akka. Actors are object-oriented in the sense that they encapsulate state and behavior, but they have much stronger isolation than regular objects in Java or Scala. The Actor model prevents sharing state between Actors and the only way to observe another actor's state is by sending it a message asking for it. Actors are extremely lightweight, they are only constrained by memory of which they consume only a few hundred bytes each — this means you can easily create millions of concurrent Actors in a single application. Their strong isolation principles together with the event-driven model (that we will talk about later on) and location transparency makes it easy to solve hard concurrency and scalability problems in an intuitive way.

You create an Actor in Java by defining a class that extends UntypedActor and implement the onReceive method (in Scala you have to extend Actor trait and implement the receive method). It is in the onReceive method that you define the behavior; how the Actor should react to the different messages it receives. An Actor can have — and often has — state. Accessing or mutating the internal state of an Actor is fully thread safe since protected by the Actor model.

So, let's now create a Greeter Actor with a single variable greeting as its state, holding on to the latest defined greeting, and in its onReceive method let's add the behavior for how it should react upon receiving the WhoToGreet and the Greet messages.

Let's start by creating our Actor in Java (you can find the code in the HelloAkkaJava.java file):


// Java code

public static class Greeter extends UntypedActor {
    String greeting = "";

    public void onReceive(Object message) {
        if (message instanceof WhoToGreet)
            greeting = "hello, " + ((WhoToGreet) message).who;

        else if (message instanceof Greet)
            getSender().tell(new Greeting(greeting), getSelf());

        else unhandled(message);
    }
}
        

Actors like this one are “untyped” in the sense that the type of message received is not restricted—it is Object as shown above. There are also typed actors, but we will not concern ourselves with those now, the normal actors are the untyped ones.

Don't worry about the getSender(), tell(..) and getSelf() API calls, we will get to that soon when we talk about sending and replying to messages.

Now let's implement it in Scala. As you can see, Scala's pattern matching features really simplify working with Actors, but apart from that it's pretty similar to the Java version (you can find the code in the HelloAkkaScala.scala file).


// Scala code

class Greeter extends Actor {
  var greeting = ""

  def receive = {
    case WhoToGreet(who) => greeting = s"hello, $who"
    case Greet           => sender ! Greeting(greeting)
  }
}
        

You will notice one difference to the Java version: here we do not explicitly pass unhandled messages to the unhandled() method. This is not necessary since the behavior defined by the receive method is expressed as a so-called partial function, which means that all messages for which no matching case statement is written down will be recognized as being not handled and Akka will automatically pass them to the unhandled() method for you.

Another difference is that the trait from which the Scala actor inherits is just called Actor. This is the Scala API while UntypedActor is the Java API for the same kind of actor.

Create our Actor

So far we have defined our Actor and its messages. Now let's create an instance of this actor. In Akka you can't create an instance of an Actor the regular way using new, instead you create it using a factory. What is returned from this factory is not an instance of the Actor itself but an ActorRef pointing to our actor instance.

This level of indirection adds a lot of power and flexibility. It enables for example location transparency meaning that the ActorRef can, while retaining the same semantics, represent an instance of the running actor in-process or on a remote machine. I.e. location doesn't matter. This also means that the runtime can if needed optimize the system by changing an actor's location or the application's topology while it is running. Another thing that this level of indirection enables is the "let it crash" model of failure management in which the system can heal itself by crashing and restarting faulty actors.

This factory in Akka is the ActorSystem and is to some extent similar to Spring's BeanFactory in that it also acts as a container for your Actors, managing their life-cycles etc. You create an Actor through the actorOf factory method. This method takes a configuration object called Props and a name. Actor (and ActorSystem) names are important in Akka, you use them for example when looking Actors up as well as when you configure them in the configuration file, so you should take your time giving your Actors good names.

This is the code that we have to write in Java:


// Java code

final ActorSystem system = ActorSystem.create("helloakka");
final ActorRef greeter = system.actorOf(Props.create(Greeter.class), "greeter");
        

The Scala code is not much different:


// Scala code

val system = ActorSystem("helloakka")
val greeter = system.actorOf(Props[Greeter], "greeter")
          

Now we have a running instance of a Greeter actor. Next we will learn how to communicate with it.

Tell the Actor (to do something)

All communication with Actors is done through asynchronous message passing. This is what makes Actors reactive and event driven. An Actor doesn't do anything unless it's been told to do something, and you tell it to do something by sending the message. Sending a message asynchronously means that the sender does not stick around waiting for the message to be processed by the recipient actor. Instead the Actor hands the message off by putting it on the recipient's mailbox and is then free to do something more important than waiting for the recipient to react on the message. The actor's mailbox is essentially a message queue and has ordering semantics, this guarantees that the ordering of multiple messages sent from the same Actor is preserved, while they can be interleaved with the messages sent by another actor.

You might be wondering what the Actor is doing when it is not processing messages, i.e. doing actual work? It is in a suspended state in which it does not consume any resources apart from memory.

You tell an Actor to do something by passing in a message into the tell method on the ActorRef. This method puts the message on the actor's mailbox and then returns immediately.


// Java code

greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());
        


// Scala code

greeter.tell(WhoToGreet("akka"), ActorRef.noSender)
        

If you are using Akka from Scala then you can also use the alias; !, called the bang operator.


// Scala code

greeter ! WhoToGreet("akka")
        

Replying to an Actor

The 'self' reference

Sometimes the communication pattern is not just a one-way style of communication but instead lends itself towards request-reply. One explicit way of doing that is by adding a reference of yourself as part of the message so the receiver can use that reference to send a reply back to you. This is such a common scenario that it is directly supported by Akka; for every message you send you have the option of passing along the sender reference (the Actor's ActorRef). If you are sending a message from within an Actor then you have access to your own ActorRef through self reference, please note that you should never use this. In Java you can access the self reference through the getSelf() method, while you can use self in Scala.


// Java code

// From within an Actor
greeter.tell(new Greet(), getSelf());
        

In Scala this is simplified a bit. Scala has something called implicit parameters which allows you to automatically and transparently pass in parameters into methods, a feature that we are taking advantage of here to automatically pass along the sender reference when you send a message to another Actor.

This code will, if invoked from within Actor 'A' automatically pass along the ActorRef of Actor 'A' as the sender of this message:


// Scala code

// From within an Actor
greeter ! Greet
        

If you choose not to pass in a sender reference into the tell method, or forget it, then a reference to the 'dead-letter' Actor will be used. The 'dead-letter' Actor is where all unhandled messages end up, and you can use Akka's Event Bus to subscribe on them.

The 'sender' reference

This sender reference will then be available in the receiver Actor when it's processing the message. Since each message is paired with its unique sender reference, the "current" sender reference will change with each new message you process. So if you for some reason need to use a specific sender reference later then you have to hold on to it, storing it away in a member field or similar. In Java you can access it using the getSender() method (while you can use sender in Scala).


// Java code

// From within the Greeter Actor
getSender().tell(new Greeting(greeting), getSelf());
        


// Scala code

// From within the Greeter Actor
sender ! Greeting(greeting)
        

Using Inbox

Most real-world Actor applications make use of more than one Actor. The inventor of the Actor Model, Carl Hewitt, recently said in an interview that; "One Actor is no Actor. Actors come in systems." This is important wisdom. To truly leverage the Actor Model you should use lots of Actors. Every hard problem in Actor programming can be solved by adding more Actors; by breaking down the problem into subtasks and delegate by handing them to new Actors.

However, for simplicity we are just using a single Actor in this sample. This means that if we communicate with this single actor from a main program then we have no sender, since we are not communicating with the Actor from within another Actor. Luckily Akka has a nice solution to this problem; Inbox.

Inbox allows you to create an "actor-in-a-box", i.e. it contains an Actor which can be used as a puppet for sending messages to other Actors and receiving their replies. You can create an Inbox using Inbox.create and send messages from it using inbox.send. The internal Actor will just put any message it receives into a queue from which it can be retrieved by calling inbox.receive; if the queue is empty then that call will block until a message becomes available. Pretty simple.

As you probably know, blocking is something that can really inhibit performance and scalability, and that you should use very sparingly and with care. That said, we are making use of it in this sample since it simplifies the sample and makes it very easy to follow the message flow.

Now let's complete this tutorial by writing the driver code that will exercise our Greeter Actor.


// Java code

// Create an "actor-in-a-box"
final Inbox inbox = Inbox.create(system);

// Tell the 'greeter' to change its 'greeting' message
greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());

// Ask the 'greeter for the latest 'greeting'
// Reply should go to the mailbox
inbox.send(greeter, new Greet());

// Wait 5 seconds for the reply with the 'greeting' message
Greeting greeting = (Greeting) inbox.receive(Duration.create(5, "seconds"));
System.out.println("Greeting: " + greeting.message);
        


// Scala code

// Create an "actor-in-a-box"
val inbox = Inbox.create(system)

// Tell the 'greeter' to change its 'greeting' message
greeter tell WhoToGreet("akka")

// Ask the 'greeter for the latest 'greeting'
// Reply should go to the mailbox
inbox.send(greeter, Greet)

// Wait 5 seconds for the reply with the 'greeting' message
val Greeting(message) = inbox.receive(5.seconds)
println(s"Greeting: $message")
        

Test the App

Both the Java and Scala examples each have unit tests in the test directory. The Java tests use JUnit, while the Scala tests use ScalaTest.

Both of these tests are making use of the excellent Akka TestKit module, which makes it so much easier to test and verify concurrent code.

Making changes to the sample's source or the test source will cause the tests to be automatically re-run.

Run the App

Congratulations!!!

Now you have almost completed the tutorial and written a simple Akka application. If you have not looked at the full sample then now is a good time to do so.

Let's have some fun and run it.

In Run, select the application to run from the drop-down list, and select Start. Feel free to modify, compile and re-run the sample.

Inspect the App

Use Inspect to see what is happening with the Actors in a running application. This will contain a list of the Actors in the Actor System. Drilling down into an individual Actor will display a number of statistics and information about the Actor. Deviations will show you any issues with your Actors.

Next Steps

The Akka Documentation explains each one of the topics covered in this tutorial in great depth, and much much more.

The manual is split up into Java and Scala versions.

The Akka Team blog; Let It Crash has a lot of articles and can be a good additional source of information.

If you have questions don't hesitate to post them to the akka-user Google Group.

comments powered by Disqus