Now lets discuss the messaging part of Actors:
Broadly these are explained in the following six steps when a message is passed to the actor:
The
Lets consider this Employee Actor as the main program and lets cal it .
As we understand from the picture, the Employee Actor,
On the other end of the spectrum, Actors are hierarchical and the ActorSystem is also similar to the
The code for initializing the ActorSystem looks like.
The
To repeat, you send messages only to the
When the message is sent to an actor, the actor’s receive method will receive the message and processes it further. receive is a partial function and has the following signature:
Here is the sample program for what we have discussed till now:
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.
The Dispatcher wraps an ExecutorService (ForkJoinPool or ThreadPoolExecutor). It executes the MailBox against this ExecutorService.
Check out this code snippet from the Dispatcher:
The method that eventually gets called when you tell a message to an
The Hr
HRActor.scala :
All that the receive method does is to,
Broadly these are explained in the following six steps when a message is passed to the actor:
- Employee creates something called an
ActorSystem
- It uses the ActorSystem to create something called as
ActorRef
. The message(MSG) is sent to the ActorRef (a proxy to HR Actor) - Actor ref passes the message along to a
Message 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 HR Actor’s receive method.
The EmployeeActor
Program.
Lets consider this Employee Actor as the main program and lets cal it . EmployeeActorApp
. As we understand from the picture, the Employee Actor,
- Creates an
ActorSystem
- Uses the
ActorSystem
to create a proxy to theHRActor (ActorRef)
- Sends the
Message
to the proxy.
Creating an Actor System
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("HrMessageingSystem")
The HrMessageingSystem
is simply a name you give to your ActorSystem
.Creating a Proxy for HR Actor
val hrActorRef:ActorRef = actorSystem.actorOf(Props[HRActor])
The actorOf
is the Actor creation method in ActorSystem
. But, as you can see, it doesn’t return a HrActor 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 HrActor 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. Send a Message to the Proxy
Now that we have an actor system and a reference to the actor, we would like to send requests to the HR actor reference. We send the message to an actor using the ! also called Tell.//send a message to the HR Actor
hrActorRef ! Message.
The Tell is also called as fire-forget. There is no acknowledgement returned from a Tell.When the message is sent to an actor, the actor’s receive method will receive the message and processes it further. receive is a partial function and has the following signature:
def receive: PartialFunction[Any, Unit]
The return type receive suggests it is Unit and therefore this function is side effecting.Here is the sample program for what we have discussed till now:
object EmployeeActorApp extends App{
//Initialize the ActorSystem
val actorSystem=ActorSystem("HrMessageingSystem")
//construct the HR Actor Ref
val hrActorRef=actorSystem.actorOf(Props[HrActor])
//send a message to the HR Actor
hrActorRef!Message
//Let's wait for a couple of seconds before we shut down the system
Thread.sleep (2000)
//Shut down the ActorSystem.
actorSystem.shutdown()
}
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 HrActor to finish off its task. The Message
We just told a Message to theActorRef
but we didn’t see the message class at all!object Message{
case class Message()
case class Message(someString:String)
}
As we know, the Message
is for the requests that come to the HrActor
. The Actor would respond back with a MessageResponse
.Dispatcher & A Mailbox
TheActorRef
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 . As Per our analogy, every HR has one mailbox too. The HR 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.
Dispatcher
Dispatcher does some really cool stuff. From the looks of it, the Dispatcher just gets the message from theActorRef
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 code snippet from the Dispatcher:
protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = {
...
try {
executorService execute mbox
...
}
HR 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 Hr
Actor
is a rudimentary class which has a List of quotes and obviously the receive method which handles the messages.HRActor.scala :
class HRActor extends Actor {
def receive = {
case s: String if(s.equalsIgnoreCase(“SICK”)=> println("Sick Leave Applied”)
case s: String if(s.equalsIgnoreCase(“PTO”) => println("PTO applied “)
}
}
The HRActor’s receive method pattern matches for the Messages passed - the Message (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 Message
- Check the message
- Check the type of the Message
- Process the message based on the type of message.
No comments:
Post a Comment