Akka Cookbook

4.7 (7 reviews total)
By Héctor Veiga Ortiz , Piyush Mishra
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Diving into Akka

About this book

Akka is an open source toolkit that simplifies the construction of distributed and concurrent applications on the JVM. This book will teach you how to develop reactive applications in Scala using the Akka framework.

This book will show you how to build concurrent, scalable, and reactive applications in Akka. You will see how to create high performance applications, extend applications, build microservices with Lagom, and more.

We will explore Akka's actor model and show you how to incorporate concurrency into your applications. The book puts a special emphasis on performance improvement and how to make an application available for users. We also make a special mention of message routing and construction.

By the end of this book, you will be able to create a high-performing Scala application using the Akka framework.

Publication date:
May 2017
Publisher
Packt
Pages
414
ISBN
9781785288180

 

Chapter 1. Diving into Akka

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
 

Introduction


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:

  1. State: An actor has internal state, which is mutated sequentially as messages are processed one by one.
  2. Behavior: An Actor reacts to messages which are sent to it by applying behavior on it.
  3. Communication: An actor communicates with other actors by sending and receiving messages to/from them.

 

  1. 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.

 

Creating an Akka Scala SBT project from scratch


Assuming that readers are Scala developers, it is obvious they have knowledge of SBT (Simple Build Tool) to build a Scala project.

Getting ready

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.

How to do it...

  1. 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

  1. 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.

  1. 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

  1. 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.

 

Creating and understanding ActorSystem


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.

Getting ready

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.

How to do it...

It is very easy to create an ActorSystem in Akka:

  1. Create a package com.packt.chapter1 inside the Hello-Akka src folder. We will keep all the source code in this package.
  2. Inside the package, create a file, say HelloAkkaActorSystem.scala, which will contain the code.
  3. Create a small scala application object, HelloAkkaActorSystem, and create an ActorSystem inside it:
        package com.packt.chapter1 
        Import akka.actor.ActorSystem 
        /** 
          * Created by user 
          */ 
        object HelloAkkaActorSystem extends App { 
          val actorSystem = ActorSystem("HelloAkka") 
          println(actorSystem) 
        } 
  1. 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

Note

Here is a way to run a single Scala application using sbt from the console. Descend to the application root directory, and run the following command:sbt "runMain com.packt.chapter1.HelloAkkaActorSystem"

How it works...

In the recipe, we create a simple Scala object creating an ActorSystem, thereafter, we run the application.

Why we need ActorSystem

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.

 

Defining the actor's behavior and state


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.

Getting ready

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.

How to do it...

  1. Open the project Hello-Akka in an IDE like intelliJ Idea, and create a Scala file, BehaviorAndState.scala, inside the package, com.packt.chapter1.
  2. 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.

  1. 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) 
        } 
  1. 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")  

 

How it works...

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's more...

There are some recommended practices related to creation of actors. For more details, you can check out the following link:

http://doc.akka.io/docs/akka/current/scala/actors.html.

 

Sending messages to actors


Sending messages to actors is the first step for building a Akka based application as Akka is a message driven framework, so get started

Getting ready

In this recipe, we will learn how to send messages to actors. Prerequisites are the same as the previous recipes.

How to do it...

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

How it works...

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.

There's more...

Visit the following link to see more information on send messages:

http://doc.akka.io/docs/akka/current/scala/actors.html#Send_messages.

 

Asking for a result from an actor


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.

How to do it...

Let's define an actor that computes something, say, the Fibonacci of a number:

  1. Create a Scala file, FibonacciActor.scala, in the package com.packt.chapter1.
  2. 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 ) 
          } 
        } 
  1. 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.

  1. Create an application which asks for result from the actor.
  2. 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._ 
  1. 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) 
        } 
  1. Run the preceding application in the IDE-like intelliJ Idea or from the console, and you will get the following output:

How it works...

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.

There's more...

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.

 

Communication between actors


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.

Getting ready

To step through this recipe we will import the Hello-Akka project in our IDE and other prerequisites are same as before.

How to do it...

We will create the following two actors here:

  • QueryActor: Sends a message to RandomNumberGenerator to generate a random number
  • RandomNumberGeneratorActor: Sends the generated random number to the QueryActor

The following are the steps for creating the actors:

  1. Create a Scala file, Communication.scala, in the package com.packt.chapter1.
  2. Create an object, Messages, which will contain the messages to be sent to the actors for communicating with each other.

 

  1. 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) 
        } 
  1. Define RandomNumberGeneratorActor, which generates a random number and sends it back to the sender.
  2. 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) 
          } 
        } 
  1. Create a queryActor, which sends messages to RandomNumberGeneratorActor 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") 
          } 
        } 

 

  1. 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) 
        } 
  1. 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

How it works...

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.

There's more...

In the following recipes, we will see how actors implement the master-slave work pulling pattern.

 

Creating a custom mailbox for an actor


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.

Getting ready

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.

How to do it...

  1. Create a Scala file, say CustomMailbox.scala, in package com.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 
  1. Define a MyMessageQueue, which extends trait MessageQueue 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()) 
            } 
          } 
        } 
  1. 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() 
        } 
  1. Create an application.conf file and put the below configuration. An application.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" 
        } 

 

  1. 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" ) 
          } 
        } 
  1. 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) 
          } 
        } 
  1. 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) 
        } 
  1. 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

How it works...

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.

 

Prioritizing messages that an actor receives


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.

 

Getting ready

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.

How to do it...

  1. Create a Scala file named PriorityMailBox.scala in package comi.packt.chapter1.
  2. 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) 
          } 
        } 
  1. 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 
        }) 

 

  1. Add this configuration to application.conf:
        prio-dispatcher {  
          mailbox-type = 
           "com.packt.chapter1..MyPriorityActorMailbox" 
        } 
  1. 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" 
        } 
  1. 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

How it works...

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.

 

Creating a control-aware mailbox for an actor


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.

Getting ready

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.

How to do it...

  1. Create a file, ControlAwareMailbox.scala, in package com.packt.chapter1.
  2. Add the following imports to the top of the file:
        import akka.dispatch.ControlMessage 
        import akka.actor.{Props, Actor, ActorSystem} 
  1. Create a control message case object as follows:
        case object MyControlMessage extends ControlMessage 
  1. 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) 
          } 
        } 

 

  1. Add the following configuration to application.conf:
         control-aware-dispatcher {  
          mailbox-type = 
           "akka.dispatch.UnboundedControlAwareMailbox" 
          //Other dispatcher configuration goes here 
        } 
  1. 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 
        } 
  1. 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?

How it works...

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.

 

Become/unbecome behavior of an actor


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.

Getting ready

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.

How to do it...

  1. Create a file named BecomeUnbecome.scala in package com.packt.chapter1.
  2. Add the following imports to the top of the file:
        import akka.actor.{Props, ActorSystem, Actor} 
  1. Define an actor which changes its behavior based on whether the state is true or false, 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) 
          } 
        } 
  1. 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?" 
        } 
  1. 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?

How it works...

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.

 

Stopping an actor


It is obvious that an actor has to be shut down gracefully after it has processed all the messages or on application shutdown.

Getting ready

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.

How to do it...

  1. Create a file, Shutdown.scala, in package com.packt.chapter1.
  2. Add the following imports to the top of file:
        import akka.actor.{PoisonPill, Props, ActorSystem, Actor} 
  1. Create a case object, Stop, as the message:
        case object Stop 
  1. 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) 
          } 
        } 
  1. 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?" 
        } 
  1. 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.

How it works...

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.

About the Authors

  • Héctor Veiga Ortiz

    Hector Veiga Ortiz is a software engineer specializing in real-time data integration. Recently, he has focused his work on different cloud technologies (such as AWS) to develop and run scalable, resilient, and high performing applications that are able to handle high volume, real-time data in diverse protocols and formats. To accomplish this task, he has been focusing his work on messaging systems such as Akka. He has also been working on microservice architectures with frameworks such as Lightbend’s Lagom. Additionally, he has a strong foundation in messaging broker knowledge, such as RabbitMQ and AMQP. Also, Hector has a master’s degree in telecommunication engineering from the Universidad Politecnica de Madrid and a master’s degree in information technology and management from the Illinois Institute of Technology.

    He currently works at HERE Technologies as part of the global traffic data integrations team and is actively developing scalable applications to consume data from several different sources. He heavily utilizes Akka to address the scalability and processing requirements. In the past, Hector worked at Xaptum Technologies, a company dedicated to M2M technologies. Moreover, he has also contributed to the Akka project on a couple of occasions and is an active StackOverflow user on the akka tag.

    Hector has also worked as a technical reviewer on the books RabbitMQ Cookbook and RabbitMQ Essentials by Packt Publishing.

    Browse publications by this author
  • Piyush Mishra

    Piyush Mishra is a professional with more than 4 years of experience of developing and designing fault-tolerant, scalable, distributed, highly performant systems using Scala, Akka, and Spark, and maintaining them across multiple servers. He is currently working as a software development engineer for R&D Labs at Pramati Labs.

    He writes a personal blog on Scala and you can also find him on LinkedIn.

    He also has presentations on Slideshare, where he talks about reactive programming and applications and why we need it. He also talks about Scala, Akka, reactive applications, and their four principles.

    Browse publications by this author

Latest Reviews

(7 reviews total)
impressive. I like read books
All perfect. Everything come as expected.
The recipe format was very effective in understanding what are otherwise challenging concepts. They authors made the process to test out the recipes very simple without minimal setup. I personally benefited in getting a better grasp of how Akka Streams work.

Recommended For You

Mastering Akka

Master the art of creating scalable, concurrent, and reactive applications using Akka

By Christian Baxter
Scala Reactive Programming

Build fault-tolerant, robust, and distributed applications in Scala

By Rambabu Posa
Scala Programming Projects

Discover unique features and powerful capabilities of Scala Programming as you build projects in a wide range of domains

By Mikaël Valot and 1 more
Scala Design Patterns - Second Edition

Learn how to write efficient, clean, and reusable code with Scala

By Ivan Nikolov