Akka Notes – Actor Messaging – 1
From the introductory first part of the Akka Notes, we saw a bird’s eye view of Actors in the Akka Toolkit. In this second part of the Akka Notes, we’ll look at the messaging part of Actors. As for the example, we would use the same Student-Teacher example that we discussed earlier.
In this first part of Actor Messaging, we’ll create the Teacher Actor and instead of the Student Actor, we’ll use a main program called StudentSimulatorApp
.
Revisiting Student-Teacher in Detail
Let’s for now consider the message sent by the StudentSimulatorApp to the TeacherActor alone. When I say StudentSimulatorApp
, I just mean a normal main program.
The picture conveys this :
(if the terms are overwhelming, don’t worry, we’ll go through them in detail)
- Student creates something called an
ActorSystem
- It uses the ActorSystem to create something called as
ActorRef
. TheQuoteRequest
message is sent to the ActorRef (a proxy to TeacherActor) - Actor ref passes the message along to a
Dispatcher
- The Dispatcher enqueues the message in the target Actor’s
MailBox
. - The Dispatcher then puts the
Mailbox
on a Thread (more on that in the next section). - The
MailBox
dequeues a message and eventually delegates that to the actual Teacher Actor’s receive method.
Like I said, don’t worry about it. Let’s look at each step in detail now. You can come back and revisit these five steps once we are done.
The StudentSimulatorApp
program
We would use this StudentSimulatorApp to bring up the JVM and initialize the ActorSystem.
As we understand from the picture, the StudentSimulatorApp
- Creates an ActorSystem
- Uses the ActorSystem to create a proxy to the Teacher Actor (ActorRef)
- Sends the QuoteRequest message to the proxy.
Let’s focus on these three points alone now.
Creating an ActorSystem
Creating a Proxy for TeacherActor?
Send a
QuoteRequest
to the Proxy
ActorSystem is the entry point into the ActorWorld. ActorSystems are through which you could create and stop Actors. Or even shutdown the entire Actor environment.
On the other end of the spectrum, Actors are hierarchical and the ActorSystem is also similar to the java.lang.Object
or scala.Any
for all Actors – meaning, it is the root for all Actors. When you create an Actor using the ActorSystem’s actorOf
method, you create an Actor just below the ActorSystem.
The code for initializing the ActorSystem looks like:
val system=ActorSystem("UniversityMessageSystem")
The UniversityMessageSystem
is simply a cute name you give to your ActorSystem.
Let’s consider the following snippet :
val teacherActorRef:ActorRef=actorSystem.actorOf(Props[TeacherActor])
The actorOf
is the Actor creation method in ActorSystem. But, as you can see, it doesn’t return a TeacherActor which we need. It returns something of type ActorRef
.
The ActorRef
acts as a Proxy for the actual Actors. The clients do not talk directly with the Actor. This is Actor Model’s way of avoiding direct access to any custom/private methods or variables in the TeacherActor or any Actor
for that sake.
To repeat, you send messages only to the ActorRef and it eventually reaches your actual Actor. You can NEVER talk to your Actor directly. People will hate you to death if you find some mean ways to do that.
It’s an one liner again. You just tell
the QuoteRequest
message to the ActorRef. The tell method in Actor is actually !
. (there’s also a tell
method in ActorRef which just delegates the call back to !
)
//send a message to the Teacher Actor teacherActorRef!QuoteRequest
That’s it !!!
If you think I am lying, check the entire code of the StudentSimulatorApp
below :
StudentSimulatorApp.scala
package me.rerun.akkanotes.messaging.firenforget import akka.actor.ActorSystem import akka.actor.Props import akka.actor.actorRef2Scala import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._ object StudentSimulatorApp extends App{ //Initialize the ActorSystem val actorSystem=ActorSystem("UniversityMessageSystem") //construct the Teacher Actor Ref val teacherActorRef=actorSystem.actorOf(Props[TeacherActor]) //send a message to the Teacher Actor teacherActorRef!QuoteRequest //Let's wait for a couple of seconds before we shut down the system Thread.sleep (2000) //Shut down the ActorSystem. actorSystem.shutdown() }
Well, I cheated a little. You’ll have to shutdown
the ActorSystem or otherwise, the JVM keeps running forever. And I am making the main thread sleep for a little while just to give the TeacherActor to finish off it’s task. I know this sounds stupid. Don’t worry about it. We’ll write some neat testcases in the next part in order to avoid this hack.
The Message
We just told a QuoteRequest
to the ActorRef but we didn’t see the message class at all !!
Here it comes :
(It is a recommended practice to wrap your messages in a nice object for easier organization)
TeacherProtocol
package me.rerun.akkanotes.messaging.protocols object TeacherProtocol{ case class QuoteRequest() case class QuoteResponse(quoteString:String) }
As you know, the QuoteRequest
is for the requests that come to the TeacherActor. The Actor would respond back with a QuoteResponse
.
Dispatcher and a MailBox
The ActorRef
delegates the message handling functionality to the Dispatcher
. Under the hood, while we created the ActorSystem
and the ActorRef
, a Dispatcher
and a MailBox
was created. Let’s see what they are about.
MailBox
Ever Actor has one MailBox (we’ll see one special case later). Per our analogy, every Teacher has one mailbox too. The Teacher has to check the mailbox and process the message. In Actor world, it’s the other way round – the mailbox, when it gets a chance uses the Actor to accomplish its work.
Also the mailbox has a queue to store and process the messages in a FIFO fashion – a little different from our regular inbox where the most latest is the one at the top.
Now, the dispatcher
Dispatcher does some really cool stuff. From the looks of it, the Dispatcher just gets the message from the ActorRef and passes it on to the MailBox. But there’s one amazing thing happening behind the scenes :
The Dispatcher wraps an ExecutorService (ForkJoinPool or ThreadPoolExecutor). It executes the MailBox
against this ExecutorService.
Check out this snippet from the Dispatcher:
protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = { ... try { executorService execute mbox ... }
What? Did you just say you execute the MailBox?
Yup. We already saw that the MailBox holds all the messages in a Queue. Also since the Executor runs the MailBox
, the MailBox must be a Thread
. You’re right. That’s pretty much MailBox’s declaration and constructor.
Here’s the signature of the Mailbox:
private[akka] abstract class Mailbox(val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable
Teacher Actor
The MailBox
, when it gets its run
method fired, dequeues a message from the message queue and passes it to the Actor
for processing.
The method that eventually gets called when you tell
a message to an ActorRef
is the receive
method of the target Actor.
The TeacherActor is a rudimentary class which has a List
of quotes and obviously the receive
method which handles the messages.
Check this out :
TeacherActor.scala
package me.rerun.akkanotes.messaging.firenforget import scala.util.Random import akka.actor.Actor import me.rerun.akkanotes.messaging.protocols.TeacherProtocol._ /* * Your Teacher Actor class. * * The class could use refinement by way of * using ActorLogging which uses the EventBus of the Actor framework * instead of the plain old System out * */ class TeacherActor extends Actor { val quotes = List( "Moderation is for cowards", "Anything worth doing is worth overdoing", "The trouble is you think you have time", "You never gonna know if you never even try") def receive = { case QuoteRequest => { import util.Random //Get a random Quote from the list and construct a response val quoteResponse=QuoteResponse(quotes(Random.nextInt(quotes.size))) println (quoteResponse) } } }
The TeacherActor’s receive method pattern matches for just one Message – the QuoteRequest
(actually, it is a good practice to pattern match the default case but there’s an interesting story to tell there)
All that the receive method does is to
- pattern match for
QuoteRequest
- pick a random quote from the static list of quotes
- construct a
QuoteResponse
- print the QuoteResponse to the console
Code
- The entire project could be downloaded from github here.
We’ll cover more interesting stuff in the parts coming up…
Reference: | Akka Notes – Actor Messaging – 1 from our JCG partner Arun Manivannan at the Rerun.me blog. |