In this chapter, we will cover the following recipes:
- Creating an Akka Scala SBT project from scratch
- Creating and understanding ActorSystem
- Defining the actor's behavior and state
- Sending messages to actors
- Asking for a result from an actor
- Communication between actors
- Creating a custom mailbox for an actor
- Prioritizing messages that an actor receives
- Creating a control-aware mailbox for an actor
- Become/unbecome behavior of an actor
- Stopping an actor
In today's world, computer hardware is becoming cheaper and more powerful, as we have multiple cores on a single CPU chip. As cores keep on increasing, with the increasing power of hardware, we need a state of the art software framework which can use these cores efficiently.
Akka is such a framework, or you can say, a toolkit, which utilizes the hardware cores efficiently and lets you write performant applications.
As we are living in big data world, a lot of traffic comes to our servers, and we want our servers to respond in milliseconds instead of seconds. Akka is here to scale up the application as the load on it increases.
We want our application to run day and night continuously with high availability--Akka is here to build fault tolerance for our application.
We want to run our application on a cluster of multiple machines--Akka is here to scale out our application across the data center.
Can we do all of this using the Java multithreading model? Maybe.
Our assumption is that most of our readers have worked with the Java multithreading model, and they are aware of the fact that it is very difficult to write multithreaded concurrent applications. This is because we have to manage low-level details like locking an object, releasing the lock on the object, notifying, waiting for threads to join each other to complete a task, and freeing up resources that a thread holds. It is difficult for us to write multithreaded programs, because we have to focus more on thread management details instead of focusing on business logic only.
Akka is a toolkit for writing truly concurrent, fault-tolerant, distributed, and scalable applications, which can run for days, months, and years without stopping, and can heal themselves in case of failure. It is very hard to write concurrent applications using the plain Java multithreading model, which also satisfies fault-tolerant, distributed, and scalable properties. Akka provides a high-level of abstraction to build such an application that satisfy these properties.
Thus, Akka provides a basic unit of abstraction of transparent distribution called actors, which form the basis for writing resilient, elastic, event-driven, and responsive systems.
Let's see what is meant by these properties:
- Resilient: Applications that can heal themselves, which means they can recover from failure, and will always be responsive, even in case of failure like if we get errors or exceptions
- Elastic: A system which is responsive under varying amount of workload, that is, the system always remains responsive, irrespective of increasing or decreasing traffic, by increasing or decreasing the resources allocated to service this workload
- Message Driven: A system whose components are loosely coupled with each other and communicate using asynchronous message passing, and which reacts to those messages by taking an action
- Responsive: A system that satisfies the preceding three properties is called responsive
A system that satisfies all four properties is called a reactive system.

Properties of reactive system
Note
For more information, see Reactive manifesto (http://www.reactivemanifesto.org).
Before starting with recipes, let's take a look at the following the actor properties:
- State: An actor has internal state, which is mutated sequentially as messages are processed one by one.
- Behavior: An Actor reacts to messages which are sent to it by applying behavior on it.
- Communication: An actor communicates with other actors by sending and receiving messages to/from them.
- Mailbox: A mailbox is the queue of messages from which an actor picks up the message and processes it.

An actor's anatomy
Actors are message-driven, that is, they are passive and do nothing unless and until you send messages to them. Once you send them a message, they pick a thread from the thread pool which is also known as a dispatcher, process the message, and release the thread back to the thread pool.
Actors are also asynchronous by nature; they never block your current thread of execution, and continue to work on another thread.
Note
Visit the Wikipedia link for an actor model (https://en.wikipedia.org/wiki/Actor_model) for details.
Let's start making recipes.
Assuming that readers are Scala developers, it is obvious they have knowledge of SBT (Simple Build Tool) to build a Scala project.
To step through this recipe, you will need SBT installed on your machine. No other prerequisites are required.
If you don't have SBT installed on your machine, please visit the SBT manual installation page(http://www.scala-sbt.org/release/docs/Manual-Installation.html), and follow the instructions for the operating system you have.
SBT is used for building Scala projects as we have Maven for Java projects. However, both SBT and Maven are capable of building Scala, Java projects.
In this book, we will build our projects on the Ubuntu Linux operating system.
- For creating an SBT project, we need to create a project directory, for example,
Hello-Akka
.
Following screenshot shows the creation of the project directory:

Creating the project directory
- Descend to the directory and run command
sbt
. We will enter into the sbt prompt mode, Now run the following commands one by one, as shown in the next screenshot:
set name := "Hello-Akka" set version := "1.0" set scalaVersion: ="2.11.7" session save exit

This will create a build file called build.sbt
and a target to put your class files into.
- Edit the build file, and add the Akka actor dependency as follows:
libraryDependencies += "com.typesafe.akka" %
"akka-actor_2.11" % "2.4.4"
We can select a specific Akka actor version against a specific Scala version in the maven repository:

Adding Akka dependency to build file
- Run the command
sbt update
; it will download the Akka dependency. Now we have the Akka actor's capabilities in our project, and we are ready to write reactive programs.
The SBT (Simple Build tool), as the name suggests is a widely used tool for building Scala projects.
In step one, we create a project directory where we keep our source files, project build definition, and target, where class files are kept for runtime execution.
In step two, we create a project build definition file, called build.sbt
, by executing simple sbt
command.
In step three, we add a library dependency in the build file for the Akka actor to enable Akka capabilities.
In step four, we download the Akka dependency using the sbt update
command, and our project is now ready for writing Akka-based applications.
This is how we can set up an Akka-based project.
In this small recipe, we will create and understand an ActorSystem. Since we are done with our initial setup of the Hello-Akka
project, we don't need to make another project for it. We need to import the SBT project in an IDE like IntelliJ Idea.
If you are using IntelliJ Idea, then you must have Scala and the SBT plugin install on it.
Note
For importing an SBT Scala project in IntelliJ Idea, visit the following website:https://www.jetbrains.com/help/idea/2016.1/getting-started-with-sbt.html?origin=old_help#import_project.
It is very easy to create an ActorSystem in Akka:
- Create a package
com.packt.chapter1
inside theHello-Akka src
folder. We will keep all the source code in this package. - Inside the package, create a file, say
HelloAkkaActorSystem.scala
, which will contain the code. - Create a small scala application object,
HelloAkkaActorSystem
, and create anActorSystem
inside it:
package com.packt.chapter1 Import akka.actor.ActorSystem /** * Created by user */ object HelloAkkaActorSystem extends App { val actorSystem = ActorSystem("HelloAkka") println(actorSystem) }
- Now, run the application in IntelliJ Idea or in the console. It will print the output as follows:
akka://HelloAkka

Downloading the Akka actor dependency
In the recipe, we create a simple Scala object creating an ActorSystem, thereafter, we run the application.
In Akka, an ActorSystem is the starting point of any Akka application that we write.
Technically, an ActorSystem is a heavyweight structure per application, which allocates n number of threads. Thus, it is recommended to create one ActorSystem per application, until we have a reason to create another one.
ActorSystem is the home for the actors in which they live, it manages the life cycle of an actor and supervises them.On creation, an ActorSystem starts three actors:
/user
- The guardian actor: All user-defined actors are created as a child of the parent actor user, that is, when you create your actor in the ActorSystem, it becomes the child of the user guardian actor, and this guardian actor supervises your actors. If the guardian actor terminates, all your actors get terminated as well./system
- The system guardian: In Akka, logging is also implemented using actors. This special guardian shut downs the logged-in actors when all normal actors have terminated. It watches the user guardian actor, and upon termination of the guardian actor, it initiates its own shutdown./
- The root guardian: The root guardian is the grandparent of all the so-called top-level actors, and supervises all the top-level actors. Its purpose is to terminate the child upon any type of exception. It sets the ActorSystem status as terminated if the guardian actor is able to terminate all the child actors successfully.
Note
For more information on ActorSystem visit: http://doc.akka.io/docs/akka/2.4.1/general/actor-systems.html.
In this recipe, we will define an actor, which will receive some messages, and apply its behavior to its state. After that, we will create that actor inside the actor system.
We will see what is meant by the terms behavior and the state of an actor.
To step through this recipe, we need to import the Hello-Akka
project in any IDE, like intelliJ Idea, and ensure that SBT is installed on our machine to build and run the Scala project from the console.
- Open the project
Hello-Akka
in an IDE like intelliJ Idea, and create a Scala file,BehaviorAndState.scala
, inside the package,com.packt.chapter1
. - Add an import to the top of the file:
import akka.actor.Actor
.
Inside the file, define the actor as follows:
class SummingActor extends Actor { // state inside the actor var sum = 0 // behaviour which is applied on the state override def receive: Receive = { // receives message an integer case x: Int => sum = sum + x println(s"my state as sum is $sum") // receives default message case _ => println("I don't know what are you talking about") } }
Here, we are not creating an actor, we are only defining the state and behavior.
- From the previous recipe, we know that ActorSystem is the home for actors, and we know how to create an ActorSystem. Now, we will create the actor inside it.
Add the following imports to the top of the file:
import akka.actor.Props import akka.actor.ActorSystem object BehaviourAndState extends App { val actorSystem = ActorSystem("HelloAkka") // creating an actor inside the actor system val actor = actorSystem.actorOf(Props[SummingActor]) // print actor path println(actor.path) }
- Run the preceding application from the IDE or from the console, and it will print the actor path.
You can run the application from the console using the following command:
sbt "runMain com.packt.chapter1.BehaviorAndState" akka://HelloAkka/user/$a
Here, HelloAkka
is the ActorSystem name, user
is the user guardian actor, that is, the parent actor for your actor, and $a
is the name of your actor.
You can also give a name to your actor:
val actor = actorSystem.actorOf(Props[SummingActor], "summingactor")
If you run the application again, it will print the actor name as summingactor
.
The output will be as follows:
akka://HelloAkka/user/summingactor
How do we create an actor if it takes an argument in the constructor as shown in the following code:
class SummingActorWithConstructor(intitalSum: Int) extends Actor { // state inside the actor var sum = 0 // behaviour which is applied on the state override def receive: Receive = { // receives message an integer case x: Int => sum = intitalSum + sum + x println(s"my state as sum is $sum") // receives default message case _ => println("I don't know what are you talking about") } }
For this, we use the following code:
actorSystem.actorOf(Props(classOf[ SummingActorWithConstructor], 10), "summingactor")
As we know from the previous recipe, the ActorSystem is a place where the actor lives.
In the preceding application, we define the actor with its state and behavior, and then create it inside Akka using the API provided by Akka.
In case of the summingactor
, the state is the variable sum
and the behavior is adding of the integer to the sum
as soon as the message arrives.
There are some recommended practices related to creation of actors. For more details, you can check out the following link:
Sending messages to actors is the first step for building a Akka based application as Akka is a message driven framework, so get started
In this recipe, we will learn how to send messages to actors. Prerequisites are the same as the previous recipes.
In the previous recipe, we created an actor which calculates the sum of integers:
val actor = actorSystem.actorOf(Props[SummingActor], "summingactor")
Now, we will send messages as integers to the summing actor, as follows:
actor ! 1
The following will be the output:
My state as sum is 1
If we keep on sending messages inside a while
loop, the actor will continue to calculate the sum incrementally:
while (true) { Thread.sleep(3000) actor ! 1 }
On sending messages inside a while
loop, the following output will be displayed:
my state as sum is 1 my state as sum is 2 my state as sum is 3 my state as sum is 4 my state as sum is 5
If we send a string message Hello
, this message will fall into the actor's default behavior case, and the output will be as follows:
I don't know what you are talking about
Actors have methods to communicate with each other actors like tell (!
) or ask (?
) where the first one is fire and forget and the second returns a Future which means the response will come from that actor in the future.
As soon as you send the message to the actor, it receives the message, picks up an underlying Java thread from the thread pool, does it's work, and releases the thread. The actors never block your current thread of execution, thus, they are asynchronous by nature.
Visit the following link to see more information on send messages:
http://doc.akka.io/docs/akka/current/scala/actors.html#Send_messages.
In this recipe, we will ask the actor to give us the result that it computes. Prerequisites are the same as the previous recipes.
In the last recipe, you learnt how to send a message using the tell-and-forget pattern. In this recipe, you will learn how to get the result from an actor after it does something.
Let's define an actor that computes something, say, the Fibonacci of a number:
- Create a Scala file,
FibonacciActor.scala
, in the packagecom.packt.chapter1
. - Add import to the top of the file:
import akka.actor.Actor
Now we define an actor which computes the Fibonacci of a number:
class FibonacciActor extends Actor { override def receive: Receive = { case num : Int => val fibonacciNumber = fib(num) } def fib( n : Int) : Int = n match { case 0 | 1 => n case _ => fib( n-1 ) + fib( n-2 ) } }
- As of now, we have defined the actor. To send the computed result back to the sender, we have to add one more line to the actor code:
sender ! fibonacciNumber
Now, notice the difference:
class FibonacciActor extends Actor { override def receive: Receive = { case num : Int => val fibonacciNumber = fib(num) sender ! fibonacciNumber } def fib( n : Int) : Int = n match { case 0 | 1 => n case _ => fib( n-1 ) + fib( n-2 ) } }
Actors, by their implementation, know the default immediate sender, that is, they know who has sent them the message.
- Create an application which asks for result from the actor.
- Add the following imports to the top of file:
import akka.actor.{Props, ActorSystem} import akka.pattern.ask import akka.util.Timeout import scala.concurrent.Await import scala.concurrent.duration._
- Create an object,
FibonacciActorApp
as follows:
object FibonacciActorApp extends App { implicit val timeout = Timeout(10 seconds) val actorSystem = ActorSystem("HelloAkka") val actor = actorSystem.actorOf(Props[FibonacciActor]) // asking for result from actor val future = (actor ? 10).mapTo[Int] val fiboacciNumber = Await.result(future, 10 seconds) println(fiboacciNumber) }
- Run the preceding application in the IDE-like intelliJ Idea or from the console, and you will get the following output:
We create an actor that computes Fibonacci number, and sends the result to the sender who sent him the message to compute the Fibonacci.
In the actor receive block, we send the Fibonacci result back to the sender. Actors, by nature, know who has sent them the message, thus we always have the sender present in the context of the receive block.
When you send a message to the actor using a question mark (?
), it returns a future promising that you will get the result when the operation would be completed.
We will learn about futures in later chapters.
To know more about sending messages to actors, go to the following link:
http://doc.akka.io/docs/akka/current/scala/actors.html#Send_messages.
In an Akka-based application, there are many actors and they will have some way to communicate among themselves..
In this recipe, you will learn how two actors communicate with each other. For this, we need to import the same project, Hello-Akka
, in our IDE. Prerequisites are the same as in the previous recipes.
To step through this recipe we will import the Hello-Akka
project in our IDE and other prerequisites are same as before.
We will create the following two actors here:
QueryActor
: Sends a message toRandomNumberGenerator
to generate a random numberRandomNumberGeneratorActor
: Sends the generated random number to theQueryActor
The following are the steps for creating the actors:
- Create a Scala file,
Communication.scala
, in the packagecom.packt.chapter1
. - Create an object,
Messages
, which will contain the messages to be sent to the actors for communicating with each other.
- Add import to the top of the file:
import akka.actor.ActorRef
After adding the import add the code that follows:
object Messages { case class Done(randomNumber: Int) case object GiveMeRandomNumber case class Start(actorRef: ActorRef) }
- Define
RandomNumberGeneratorActor
, which generates a random number and sends it back to the sender. - Add the two imports given next to the top of the file:
import akka.actor.Actor import scala.util.Random._
Now add the code that follows:
class RandomNumberGeneratorActor extends Actor { import Messages._ override def receive: Receive = { case GiveMeRandomNumber => println("received a message to generate a random integer") val randomNumber = nextInt sender ! Done(randomNumber) } }
- Create a
queryActor
, which sends messages toRandomNumberGeneratorActor
and receives the random number:
class QueryActor extends Actor { import Messages._ override def receive: Receive = { case Start(actorRef) => println(s"send me the next random number") actorRef ! GiveMeRandomNumber case Done(randomNumber) => println(s"received a random number $randomNumber") } }
- Create an application object,
Communication
, to see the output:
object Communication extends App { import Messages._ val actorSystem = ActorSystem("HelloAkka") val randomNumberGenerator = actorSystem.actorOf(Props[RandomNumberGeneratorActor], "randomNumberGeneratorActor") val queryActor = actorSystem.actorOf(Props[QueryActor], "queryActor") queryActor ! Start(randomNumberGenerator) }
- Now run the application in the IDE or from the console, and the output will be displayed as follows:
send me the next random number received a message to generate a random integer received a random number 841431704
In step two, we see there is message object, which contains messages to be sent to the actors. Actors will use these messages for communication.
In step three, we define RandomNumberGeneratorActor
, which receives the message GiveMeRandomNumber
, and sends it to the sender as follows:
sender ! Done(randomNumber)
In step four, we define QueryActor
, which actually sends the message to RandomNumberGenerator
, and receives the result in case of Done
.
In step five, we create a test application to see the execution flow of the whole message.
In this recipe, you will learn how to create a custom mailbox for an actor. As you're already aware, in Akka, each actor has its own mailbox-like queue from which it picks up the messages one by one, and processes them. There are some custom mailbox implementations provided by Akka, such as PriorityMailbox and controlAwareMailbox, other than the default mailbox.
There might be a situation when you want to control the way the actor picks up the message or anything else. We will create an actor mailbox that will accept messages from actors of a particular name.
To step through this recipe, we need to import our Hello-Akka
project in the IDE-like intelliJ Idea. Prerequisites are the same as those in the previous recipes.
- Create a Scala file, say
CustomMailbox.scala
, in packagecom.packt.chapter1
.
Add the following required imports to the top of the file:
import java.util.concurrent.ConcurrentLinkedQueue import akka.actor.{Props, Actor, ActorSystem,ActorRef} import akka.dispatch.{ MailboxType, ProducesMessageQueue, Envelope, MessageQueue} import com.typesafe.config.Config
- Define a
MyMessageQueue
, which extends traitMessageQueue
and implementing methods:
class MyMessageQueue extends MessageQueue { private final val queue = new ConcurrentLinkedQueue[Envelope]() // these should be implemented; queue used as example def enqueue(receiver: ActorRef, handle: Envelope): Unit = { if(handle.sender.path.name == "MyActor") { handle.sender ! "Hey dude, How are you?, I Know your name,processing your request" queue.offer(handle) } else handle.sender ! "I don't talk to strangers, I can't process your request" } def dequeue(): Envelope = queue.poll def numberOfMessages: Int = queue.size def hasMessages: Boolean = !queue.isEmpty def cleanUp(owner: ActorRef, deadLetters: MessageQueue) { while (hasMessages) { deadLetters.enqueue(owner, dequeue()) } } }
- Let's provide a custom mailbox implementation, which uses the preceding
MessageQueue
:
class MyUnboundedMailbox extends MailboxType with ProducesMessageQueue[MyMessageQueue] { def this(settings: ActorSystem.Settings, config: Config) = { this() } // The create method is called to create the MessageQueue final override def create(owner: Option[ActorRef], system:: Option[ActorSystem]):MessageQueue = new MyMessageQueue() }
- Create an
application.conf
file and put the below configuration. Anapplication.conf
file is used to configure Akka application properties and it resides in the project's resource directory.
custom-dispatcher { mailbox-requirement = "com.packt.chapter1.MyMessageQueue" } akka.actor.mailbox.requirements { "com.packt.chapter1.MyMessageQueue" = custom-dispatcher- mailbox } custom-dispatcher-mailbox { mailbox-type = "com.packt.chapter1.MyUnboundedMailbox" }
- Now define an actor that would use the preceding configuration, say,
MySpecialActor
. It's special, because it would talk to the actor whom it knows, and say hello to that actor only:
class MySpecialActor extends Actor { override def receive: Receive = { case msg: String => println(s"msg is $msg" ) } }
- Define an actor who will try to talk to the special actor:
class MyActor extends Actor { override def receive: Receive = { case (msg: String, actorRef: ActorRef) => actorRef ! msg case msg => println(msg) } }
- Create a test application,
CustomMailbox
, as follows:
object CustomMailbox extends App { val actorSystem = ActorSystem("HelloAkka") val actor = actorSystem.actorOf(Props[MySpecialActor].withDispatcher ("custom-dispatcher")) val actor1 = actorSystem.actorOf(Props[MyActor],"xyz") val actor2 = actorSystem.actorOf(Props[MyActor],"MyActor") actor1 ! ("hello", actor) actor2 ! ("hello", actor) }
- Run the application in the IDE or from the console, and you will get the following output:
I don't talk to strangers, I can't process your request Hey dude, How are you?, I Know your name,processing your request msg is hello
As you know, a mailbox uses a message queue, and we need to provide a custom implementation for the queue.
In step two, we define a class, MyMessageQueue
, which extends the trait MessageQueue
and the implementing methods.
We want our actor to receive messages from only those actors whose name is MyActor
, and not from any other actor.
To achieve the aforementioned functionality, we implement the enqueue
method, and specify that the message should be enqueued if sender name is MyActor
, otherwise ignore the message.
In this case, we used ConcurrentLinkedQueue
as the underlying data structure for the queue.
However, it is up to us which data structure we pick for enqueing and removing messages. Changing the data structure may also change the processing order of messages.
In step three, we define the custom mailbox using MyMessageQueue
.
In step four, we configure the preceding mailbox with a custom-dispatcher
in application.conf
.
In step five and six, we define MySpecialActor
, which will use the custom mailbox when we create it with the custom-dispatcher
. MyActor
is the actor which tries to communicate with MySpecialActor
.
In step seven, we have two instances of MyActor
, actor1
and actor2
, which send messages to MySpecialActor
.
Since MySpecialActor
talks to only those Actors whose name is MyActor
, it does not process messages from MyActor
whose name is xyz
, as you can see in the output.
There are situations when you want your actor to process some particular messages first, and then move on to others. This means you want to give priority to some messages over others.
For such scenarios, Akka has comes up with priority mailbox, which lets you prioritize messages.
To step through this recipe, we need to import our Hello-Akka
project in IDE-like IntelliJ Idea. Prerequisites are the same as those in previous recipes.
- Create a Scala file named
PriorityMailBox.scala
in packagecomi.packt.chapter1
. - Create an actor called
MyPriorityActor
as follows:
class MyPriorityActor extends Actor { def receive: PartialFunction[Any, Unit] = { // Int Messages case x: Int => println(x) // String Messages case x: String => println(x) // Long messages case x: Long => println(x) // other messages case x => println(x) } }
- To prioritize the messages, create a priority mailbox as follows:
class MyPriorityActorMailbox(settings: ActorSystem.Settings, config: Config) extends UnboundedPriorityMailbox ( // Create a new PriorityGenerator, lower prio means more important PriorityGenerator { // Int Messages case x: Int => 1 // String Messages case x: String => 0 // Long messages case x: Long => 2 // other messages case _ => 3 })
- Add this configuration to
application.conf
:
prio-dispatcher { mailbox-type = "com.packt.chapter1..MyPriorityActorMailbox" }
- Create an application,
PriorityMailBoxApp
, as shown in the following code:
object PriorityMailBoxApp extends App { val actorSystem = ActorSystem("HelloAkka") val myPriorityActor = actorSystem.actorOf(Props[MyPriorityActor].withDispatcher ("prio-dispatcher")) myPriorityActor ! 6.0 myPriorityActor ! 1 myPriorityActor ! 5.0 myPriorityActor ! 3 myPriorityActor ! "Hello" myPriorityActor ! 5 myPriorityActor ! "I am priority actor" myPriorityActor ! "I process string messages first,then integer, long and others" }
- Run the application in IDE or from the console. The following output will be displayed:
Hello I process string messages first,then integer, long and others I am priority actor 1 3 5 6.0 5.0
In step two, we just define an actor which processes Int
, Long
, String
, and other messages.
In step four, we configure a prio-dispatcher
with this MyPriorityActorMailbox
.
In step five, we create an actor which will use the prio-dispatcher
.
In step six, as we can see in the output, the string messages are processed first, because they were given highest priority.
There are some situations when you want your actor to process a certain message first before any other message, at any point of time. This means that you can tell an actor to do some particular work before doing any other job.
To step through this recipe, we need to import our Hello-Akka
project in IDE-like IntelliJ Idea. Prerequisites are the same as those of the previous recipes.
- Create a file,
ControlAwareMailbox.scala
, in packagecom.packt.chapter1
. - Add the following imports to the top of the file:
import akka.dispatch.ControlMessage import akka.actor.{Props, Actor, ActorSystem}
- Create a control message case object as follows:
case object MyControlMessage extends ControlMessage
- Define an actor:
class Logger extends Actor { def receive = { case MyControlMessage => println("Oh, I have to process Control message first") case x => println(x.toString) } }
- Add the following configuration to
application.conf
:
control-aware-dispatcher { mailbox-type = "akka.dispatch.UnboundedControlAwareMailbox" //Other dispatcher configuration goes here }
- Create a test application in which we can send a message to the preceding application, and it will process the control message first:
object ControlAwareMailbox extends App { val actorSystem = ActorSystem("HelloAkka") val actor = actorSystem.actorOf(Props[Logger].withDispatcher( "control-aware-dispatcher")) actor ! "hello" actor ! "how are" actor ! "you?" actor ! MyControlMessage }
- Run the application in IDE or from the console. You will get the following output:
Oh, I have to process Control message first hello how are you?
In step three, we create an object, MyControlMessage
, which extends the ControlMessage
.
ControlMessage
is a trait. The message which extends this trait will be handled on priority by ControlAwareMailbox
. ControlAwareMailbox
maintains two queues to allow messages that extend ControlMessage
to be delivered with priority.
In step four, we create an actor which will handle ControlMessage
.
In step five, we configure the control-aware-dispatcher
in application.conf
.
In step six. we create the actor with control-aware-dispatcher
.
In step seven, we are able to see in the output that the actor processed ControlMessage first
.
In some situations, we want our actor to change its behavior based on its state. This means that there are cases where an actor receives a message, and if its state changes or transitions, it changes the way further messages should be handled.
Thus, using become/unbecome, we can hot swap the actor functionality at runtime.
To step through this recipe, we need to import the Hello-Akka
project in the IDE-like IntelliJ Idea. Prerequisites are the same as those in previous recipes.
- Create a file named
BecomeUnbecome.scala
in packagecom.packt.chapter1
. - Add the following imports to the top of the file:
import akka.actor.{Props, ActorSystem, Actor}
- Define an actor which changes its behavior based on whether the state is
true
orfalse
, as shown in the following code:
class BecomeUnBecomeActor extends Actor { def receive: Receive = { case true => context.become(isStateTrue) case false => context.become(isStateFalse) case _ => println("don't know what you want to say !! ") } def isStateTrue: Receive = { case msg : String => println(s"$msg") case false => context.become(isStateFalse) } def isStateFalse: Receive = { case msg : Int => println(s"$msg") case true => context.become(isStateTrue) } }
- Create a test application,
BecomeUnBecomeApp
, as follows:
object BecomeUnBecomeApp extends App { val actorSystem = ActorSystem("HelloAkka") val becomeUnBecome = actorSystem.actorOf(Props[BecomeUnBecomeActor]) becomeUnBecome ! true becomeUnBecome ! "Hello how are you?" becomeUnBecome ! false becomeUnBecome ! 1100 becomeUnBecome ! true becomeUnBecome ! "What do u do?" }
- Run the application in an IDE like IntelliJ Idea or from the console; the output will be as follows:
Hello how are you? 1100 What do u do?
In step two, we define an actor, which changes its state to handle string and integer values.
If the state is true
, we set the behavior as context.become(isStateTrue)
, and it starts handling string messages. If the state is false
, we set the behavior as context.become(isStateFalse)
, and it starts handling integer messages.
In step four, we create the actor and send it to see if the output matches the functionality.
It is obvious that an actor has to be shut down gracefully after it has processed all the messages or on application shutdown.
To step through this recipe, we need import the Hello-Akka
project in an IDE like IntelliJ Idea. Prerequisites are the same as those in previous recipes.
- Create a file,
Shutdown.scala
, in packagecom.packt.chapter1
. - Add the following imports to the top of file:
import akka.actor.{PoisonPill, Props, ActorSystem, Actor}
- Create a case object,
Stop
, as the message:
case object Stop
- Define an actor,
ShutdownActor
, as follows:
class ShutdownActor extends Actor { override def receive: Receive = { case msg:String => println(s"$msg") case Stop => context.stop(self) } }
- There are two ways we can stop the actor:
- Using
PoisonPill
- Using
context.self(actorRef)
Create an actor and send it a message as shown in the following code:
object ShutdownApp extends App{ val actorSystem = ActorSystem("HelloAkka") val shutdownActor1 = actorSystem.actorOf(Props[ShutdownActor], "shutdownActor1") shutdownActor1 ! "hello" shutdownActor1 ! PoisonPill shutdownActor1 ! "Are you there?" val shutdownActor2 = actorSystem.actorOf(Props[ShutdownActor], "shutdownActor2") shutdownActor2 ! "hello" shutdownActor2 ! Stop shutdownActor2 ! "Are you there?" }
- Run the preceding application, and you will get the following output:
hello hello [INFO] [05/22/2016 20:39:53.137] [HelloAkka-akka.actor.default- dispatcher-4] [akka://HelloAkka/user/shutdownActor1] Message [java.lang.String] from Actor[akka://HelloAkka/deadLetters] to Actor[akka://HelloAkka/user/shutdownActor1#417818231] was not delivered. [1] dead letters encountered. [INFO] [05/22/2016 20:39:53.138] [HelloAkka- akka.actor.default-dispatcher-4] [akka://HelloAkka/user/shutdownActor2] Message [java.lang.String] from Actor[akka://HelloAkka/deadLetters] to Actor[akka://HelloAkka/user/shutdownActor2#788021817] was not delivered. [2] dead letters encountered.
In step three, we create a Stop
message. Upon receiving this message, the actor will stop using context.stop(self)
.
In step four, we define an actor which handles the Stop
message.
In step five, we create two actors of the same class, shutdownActor1
and shutdownActor2
. We shut down shutdownActor1
using PoisonPill
and shutdownActor2
using context.stop(self)
.
PoisonPill
and context.stop(self)
are the two ways to kill an actor. PoisonPill
is the inbuilt message that is handled after all the messages that were already queued in the mailbox.
Context.stop
is basically used for an ordered shutdown of actors when you want the child actors to stop first, then the parent actor, followed by the ActorSystem to stop top-level actors.