Table of Contents
This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 13.1, “How to get started with a simple Scala/Akka Actor.”
Problem
You want to begin using Akka actors to build concurrency into your Scala applications.
Solution
Create an actor by extending the akka.actor.Actor
class and writing a receive
method in your class. The receive
method should be implemented with a case
statement that allows the actor to respond to the different messages it receives.
To demonstrate this, create an SBT project directory named HelloAkka
, move into that directory, and then add the necessary Akka resolver and dependency information to your build.sbt file:
name := "Hello Test #1" version := "1.0" scalaVersion := "2.10.0" resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.1.2"
At the time of this writing, the Akka actor library is being migrated into the Scala distribution, but it’s still necessary to include the library as a dependency in your SBT build.sbt file (or download the necessary JAR files manually). This may change in the future, in which case the dependencies shown in this chapter may not be necessary.
Next, define an actor that responds when it receives the String
literal hello
as a message. To do this, save the following source code to a file named Hello.scala in the root directory of your SBT project. Notice how the literal hello
is used in the first case
statement in the receive
method of the HelloActor
class:
import akka.actor.Actor import akka.actor.ActorSystem import akka.actor.Props class HelloActor extends Actor { def receive = { case "hello" => println("hello back at you") case _ => println("huh?") } } object Main extends App { // an actor needs an ActorSystem val system = ActorSystem("HelloSystem") // create and start the actor val helloActor = system.actorOf(Props[HelloActor], name = "helloactor") // send the actor two messages helloActor ! "hello" helloActor ! "buenos dias" // shut down the system system.shutdown }
Then run the application like this:
$ sbt run
After SBT downloads the Akka JAR files and their dependencies, you should see the following output from the println
statements in the HelloActor
class:
[info] Running Main hello back at you huh?
Discussion
Here’s a step-by-step description of the Scala/Akka code:
- The
import
statements import the members that are needed. - An
Actor
namedHelloActor
is defined. HelloActor
’s behavior is implemented by defining areceive
method, which is implemented using amatch
expression.- When
HelloActor
receives theString
literalhello
as a message, it prints the first reply, and when it receives any other type of message, it prints the second reply. - The
Main
object is created to test the actor. - In
Main
, anActorSystem
is needed to get things started, so one is created. TheActorSystem
takes a name as an argument, so give the system a meaningful name. The name must consist of only the[a-zA-Z0-9]
characters, and zero or more hyphens, and a hyphen can’t be used in the leading space. - Actors can be created at the
ActorSystem
level, or inside other actors. At theActorSystem
level, actor instances are created with thesystem.actorOf
method. ThehelloActor
line shows the syntax to create anActor
with a constructor that takes no arguments. - Actors are automatically started (asynchronously) when they are created, so there’s no need to call any sort of “start” or “run” method.
- Messages are sent to actors with the
!
method, andMain
sends two messages to the actor with the!
method:hello
andbuenos dias
. helloActor
responds to the messages by executing itsprintln
statements.- The
ActorSystem
is shut down.
That’s all you need to create and use your first Akka Actor
.
Details
When implementing the behavior of an Akka actor, you should define a receive
method using a match
expression, as shown in the example. Your method should handle all potential messages that can be sent to the actor; otherwise, an UnhandledMessage
will be published to the ActorSystem
’s EventStream
. As a practical matter, this means having the catch-all case _
line in your match
expression.
In this example, messages were sent to the HelloActor
class as String
literals, but other recipes will show how to send messages to actors using other types. Messages should be immutable, so for simple examples, a String
works well.
ActorSystem
The API documentation describes an ActorSystem
like this:
“An actor system is a hierarchical group of actors which share common configuration, e.g. dispatchers, deployments, remote capabilities and addresses. It is also the entry point for creating or looking up actors.”
An ActorSystem
is the structure that allocates one or more threads for your application, so you typically create one ActorSystem
per (logical) application.
As an example, I wrote a “speech interaction” application named SARAH that lets me interact with a Mac OS X computer using only voice commands. Besides allowing interactive commands, SARAH also runs background tasks to check my email, notify me of Facebook and Twitter events, stock prices, etc.
SARAH uses a plug-in architecture, so there are plug-ins for each major area of functionality (such as an email plug-in, Facebook plug-in, Twitter plug-in, etc.). A plug-in typically has one parent actor that delegates work to child actors as necessary. All of these plug-ins run under one ActorSystem
.
When SARAH starts, it starts the ActorSystem
using the same method shown in the Solution. Once started, it creates three main actors named brain
, ears
, and `mouth, and then starts its plug-ins.
As an interesting experiment with the ActorSystem
, remove the system.shutdown
line at the end of the Main
object. You’ll see that the application doesn’t terminate, because the actors and system are still running. (Press Control-C to terminate the application.)
Akka ActorRef
When you call the actorOf
method on an ActorSystem
, it starts the actor asynchronously and returns an instance of an ActorRef
. This reference is a “handle” to the actor, which you can think of as being a façade or broker between you and the actual actor. This façade keeps you from doing things that would break the Actor
model, such as reaching into the Actor
instance and attempting to directly mutate variables. Tasks like this should only be done by passing messages to the actor, and the hands-off approach of an ActorRef
helps reinforce proper programming practices.
(Again, think of an actor as a person you can only communicate with by placing messages in his mailbox.)
The Akka documentation states that an ActorRef
has these qualities:
- It is immutable.
- It has a one-to-one relationship with the
Actor
it represents. - It is serializable and network-aware. This lets you pass the
ActorRef
around the network.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |