akka : ‘hello world’

So last time I outlined the road map for this series of articles on Akka, and posted up some information from the Akka creators on what they had to say about Akka.

This time we will look at a simple example of Akka.

But just before we do that, let’s talk a bit more about WHY I think Akka is great stuff.

I have been a .NET programmer for many years and have seen asynchronous programming come in many different flavors now

  • Asynchronous delegates
  • BackgroundWorker
  • Task (TPL)
  • Async Await
  • RX
  • Concurrent collections
  • Critical sections (synchronized sections of code)

All of these pretty much have their JVM equivalent, and what you would have likely seen if you have used the .NET or JVM equivalents is the used of locks from time to time. For example under the covers the the concurrent collections would still use some locking (monitor enter/exit) to achieve the critical sections

This is all good stuff, and has got better to work with over the years, but there could be better more elegant lock free way of working with concurrent/parallel programming.

For me this is what Akka brings to the table. Instead of working with shared state that MUST be protected when writing multithreaded code, we simply don’t use any shared state and create dedicated micro sized bits of code that deal with one thing and one thing only. These are called “Actors”.

Actors do NOT share state instead they work independently of each other and rely on message passing. Where the message payload should give the actor either everything it needs to do it’s job (or at the very least enough information to perhaps look things up, say an Id such that Actor can look up the entity required by its Id field).

At no point will we be using locks within actors.

Ok so that is my mini-rant/intro over. Lets now carry on and have a look at what it takes to write some Akka code in Scala.

What Libs Do We Need?

As I mentioned in the introduction post I will be using Scala exclusively to do this series of posts. As such I shall also be using SBT to do the build side of things.

So for this post we are only showing how to use simple actors so we don’t have to pull in that many dependencies, we can keep things simple and use the following “build.sbt” file, where I am pulling in the following 2 dependencies

  • Basic Akka stuff
  • Joda time
name := "HelloWorld"

version := "1.0"

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  "com.typesafe.akka" % "akka-actor_2.11" % "2.4.8",
  "joda-time" % "joda-time" % "2.9.4")

NOTE : This SBT set of dependencies may grow in subsequent articles, but where it does require pulling in more Akka JARs I will show that when the time comes.

 

How Do We Create An Actor System?

To be to use the Akka actor system, we must first create an Akka system that is the fabric that all actors run under. This is easily achieved as follows:

object Demo extends App {

  //create the actor system
  val system = ActorSystem("HelloSystem")

  //---------------------------
  //   EXTRA STUFF WILL GO HERE
  //---------------------------


  //shutdown the actor system
  system.terminate()

  StdIn.readLine()
}

Note that you should ensure that the Akka system is also shutdown correctly.

The example I show here is a simple console type application, so my startup/shutdown logic is all in the same file, but in a real production app, things may be more complex (well they should be I would hope).

 

How Do We Create An Actor?

Now that we have an actor system, the next thing we need to do is create some actors that will live within the actor system. I used the word live as a ownership type of arrangement.

So how do we create an actor exactly?

Well luckily this to is dead simple we just need to inherit from Actor and provide an implementation for the receive method to handle the different messages that may be sent to the actor.

Recall that an actor works by receiving messages and acting upon them.

Here is what the skeleton code may look like:

import akka.actor.Actor

class HelloActor extends Actor {
  def receive = {
    //DO THE MESSAGE HANDLING HERE
  }
}

We will talk more about the receive method in a while, for now just know that you must implement this method for an Akka actor to work correctly

Difference Between Tell And Ask

Just before we get on to seeing the examples, lets just take a brief diversion where we talk about the difference between ask and tell.

When we ask (? method in scala) an actor we expect a response by way of a Future[T], this is an asynchronous operation.

When we tell (! method in scala) an actor something this is analogous to fire and forget (of course the receiving actor could send a response back to the initiating actor via a different message, but that’s a different story), this is an asynchronous operation that returns immediately.

Sender

We have not covered this ground yet but we will in one of the subsequent posts, but for now all you need to know is that when you are sending messages to an actor, you do so by a construct called actorRef which is a kind of like a handle to an actor.

There are special types of actorRef one such case being “sender” who is the initiator actorRef of the message being received (if we are talking from the context of the receiving actor). You will see “sender” used in the examples below.

How Do We Send A Message To An Actor?

Here is how we would send a message to an actor. This is a tell (!) so is fire and forget.

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.io.StdIn
import scala.util.{Success, Failure}
import ExecutionContext.Implicits.global

object Demo extends App {

  //create the actor system
  val system = ActorSystem("HelloSystem")

  // default Actor constructor
  val helloActor = system.actorOf(Props[HelloActor], name = "helloactor")

  //send some messages to the HelloActor (fire and forget)
  helloActor ! "hello"
  helloActor ! "tis a fine day for Akka"

  //shutdown the actor system
  system.terminate()

  StdIn.readLine()
}

Where we have the following HelloActor implementation

import akka.actor.Actor

class HelloActor extends Actor {
  def receive = {
    case "hello" => println("world")
    case _       => println("unknown message")
  }
}

See how for this simple actor we only ever deal with 2 things in the receive method

  • “Hello”
  • Anything else

It is consired good practice to ensure that you handle the correct messages and deal with unknown messages too

How Do We Wait For A Response From An Actor?

So we just saw a tell (fire and forget) but how about an ask. This is slightly harder but not much, we simply have to deal with the fact that a Future[T] will be the result of an ask. There are numerous ways of dealing with that, assuming we have the following actor

import akka.actor.Actor

class AskActor extends Actor {
  def receive = {
    case GetDateMessage => sender ! new org.joda.time.DateTime().toDate().toString()
    case _       => println("unknown message")
  }
}

Here are some examples of how to deal with the result of the ask

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.io.StdIn
import scala.util.{Success, Failure}
import ExecutionContext.Implicits.global

object Demo extends App {

  //create the actor system
  val system = ActorSystem("HelloSystem")

  // default Actor constructor
  val askActor = system.actorOf(Props[AskActor], name = "askactor")

  //send some messages to the AskActor, we want a response from it

  // (1) this is one way to "ask" another actor for information
  implicit val timeout = Timeout(5 seconds)
  val future1 = askActor ? GetDateMessage
  val result1 = Await.result(future1, timeout.duration).asInstanceOf[String]
  println(s"result1=$result1")

  // (2) a slightly different way to ask another actor for information
  val future2: Future[String] = ask(askActor, GetDateMessage).mapTo[String]
  val result2 = Await.result(future2, 5 second)
  println(s"result2=$result2")

  // (3) don't use blocking call at all, just use future callbacks
  val future3: Future[String] = ask(askActor, GetDateMessage).mapTo[String]
  future3 onComplete {
    case Success(result3) =>  println(s"result3=$result3")
    case Failure(t) => println("An error has occured: " + t.getMessage)
  }


  //shutdown the actor system
  system.terminate()

  StdIn.readLine()
}

Piping Futures

Another use case you may have is that you may want to use Future[T] internally within the actor code and send Future[T] around from actor to actor. Akka also supports this by the use of the pipe pattern, which you can use like this where we are piping the Future[List[Int]] back to the sender

import akka.actor._
import akka.pattern.pipe
import scala.concurrent.{ExecutionContext, Future}
import ExecutionContext.Implicits.global

class FutureResultActor extends Actor {
  def receive = {
    case GetIdsFromDatabase => {
      Future(List(1,2,3)).pipeTo(sender)
    }
    case _       => println("unknown message")
  }
}

Where the code that initiated the sending of the GetIdsFromDatabase message looks like this (the sender in the code above)

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.io.StdIn
import scala.util.{Success, Failure}
import ExecutionContext.Implicits.global

object Demo extends App {

  //create the actor system
  val system = ActorSystem("HelloSystem")

  // default Actor constructor
  val futureResultActor = system.actorOf(Props[FutureResultActor], name = "futureresultactor")

  //send some messages to the FutureResultActor, we expect a Future back from it
  val future4: Future[List[Int]] = ask(futureResultActor, GetIdsFromDatabase).mapTo[List[Int]]
  future4 onComplete {
    case Success(result4) =>  println(s"result4=$result4")
    case Failure(t) => println("An error has occured: " + t.getMessage)
  }


  //shutdown the actor system
  system.terminate()

  StdIn.readLine()
}

 

Where Is The Code?

As previously stated all the code for this series will end up in this GitHub repo:

https://github.com/sachabarber/SachaBarber.AkkaExamples

Advertisements

2 thoughts on “akka : ‘hello world’

  1. Eric says:

    Hi Sacha. I’m just getting started with Scala. I had a basic understanding of the Actor model without ever getting my hands dirty. Looking forward to your series 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: