Actors, Messages and Behaviors

Daniel Ciocîrlan
A free video tutorial from Daniel Ciocîrlan
Software Engineer & Best-Selling Instructor
4.7 instructor rating • 11 courses • 67,303 students

Learn more from the full course

Akka Essentials with Scala | Rock the JVM

Learn the Akka actor model with Scala and write parallel, concurrent and fault-tolerant systems

12:46:42 of on-demand video • Updated March 2021

  • create concurrent applications with actors instead of threads and locks
  • design fault-tolerant systems with supervision
  • configure Akka for various scenarios
  • confidently test actor systems
  • use Akka patterns and best practices
English [Auto] All right, welcome back. I'm Daniel, and in this video, we are going to see the actor principles straight in the code, even if we have only a vague intuition about what's going on. So don't worry about it. And later, we will explore how these principles solve our earlier frustrations with the thread model and learn how actors actually work under the hood. All right. So we're back to our Idy. And because we started a new section, let's go ahead and create a special package for this section only. So. Right. Click on the scallop package here, new package and let's name this part to actors. And under the newly created part to actors package, let's create a new sculler application. So right click new class. Let's name this actor's intro and let's make this an object. And extends up as usual. Cool. Now, every application will have to start with what is called an actor system. So this is the part one actor systems. The way that we create an actor system is the thing that we did in the playground when we first set up our project. So we would create something like an actor system and we would say actor system. So the applied method of the actor system class, just auto imported. And let's give it a name. Let's call this first actor system. And if everything goes well, if we print line after system name, we should be able to see this string to the console. So let's run this and make sure this runs fine. All right, so we have our first actor system, the actress system is a heavyweight data structure that controls a number of threads under the hood, which then allocates to running actors. We will see how actors work very shortly. Now, it's recommended to have one of these actress systems, for application instance, unless we have good reasons to create more. OK, and also the name of this actor system has restrictions, so it must contain only alphanumeric characters. So normal characters and non-leading hyphens or underscores. That's because actors can be located by their actors system and we cannot have, for example, spaces inside if we try to do this with a space. This program will crash because we have our illegal name. Now that we have our electoral system, we are ready to move to the more interesting part to where we create actors within our electoral system. So as we mentioned in the previous video, actors are kind of like humans talking to each other. So when you want to interact with another human, you send a message, for example, something like where can I find the supermarket? And the other actor receives the message when they can hear it or when they are busy doing something else. OK, they think about it or they process your message and they may or may not reply back something like go there and take the second right. And so on and so forth. OK, so we now remember the main properties of this interaction. First of all, an actor is uniquely identified, much like humans are uniquely identified by their face or by their Social Security number and things like that. OK, so an actor is uniquely identified within an actor system. Secondly, messages are passed and processed asynchronously. So you send the message when you need and the actors reply when they can. Third, each actor has a unique behavior or a unique way of processing the message. Thinking back to our human interaction, if that human who you're asking where the supermarket is doesn't like your face, they might not reply back or they might reply with an angry remark or something like that. OK, and finally, you cannot ever invade the other actor or read their mind or otherwise force them to give you the information that you want. So having said that, let's create our first actor. Let's say our first actor counts words. So let's create our first word count actor. And the way we do that in action is by declaring a class, let's call this word count actor. And this derives from the actor trait. So we will auto input actor. And in order for this class to work, we need to define a method called receive. Notice that the IDY wants to autocomplete this for us, but I'm going to write this by hand. So the method receives gets no arguments and its return type is a partial function from any two unit. And let's create a little case, let's say we have a message, which is a string and we split this message by space's so message split. By spaces and this word count actor has an internal variable. Let's call this total words, which I initialized with the zero, and his total words is incremented by the number of words in this message. So let's say total words plus equals message, split space, dot length. So what we have done here is the definition of an actor which has some internal data and the behavior or the receive handler that Akka will invoke. So the way that we would communicate with this actor would be first to instantiate an actor and then send a message, let's say, in case we receive anything else, let's print some unknown message to the council. So let's print word counter and I cannot understand. And say message or MSG to string. OK, so we would go to part three now where we would instantiate our actor. Now, the difference between actors and normal objects in action is that you cannot instantiate an actor by calling you, but by using invoking the actor system. So the way that we do that is saying, well, let's call this word counter equals and watch what I'm going to say. Actors system dot actor of and I'm going to pass in an object called props of type word count actor. Let's autocomplete this because we don't have it in our scope and then let's give it a name, word counter. So this is the way that we instantiate anactor, you cannot say vile word counter equals a new word count actor that doesn't work, OK? In order to have a proper actor managed by AKA, you need to have a system and then call its actor of method and then press in a props object typed with the actor type that you want to instantiate. The other parameter here on the actor of Method is the name of your actor. It's often a good idea to name your actors in practice and the name restrictions for the actors are the same as for the actors system. So you only can use alphanumeric characters and non-leading hyphens and underscores. And having done that, the result of this expression is an actor reference. So an actor reference is the data structure that exposes to you as a programmer so that you cannot call or otherwise poke into the actual word count actor, for instance, the actor creates. You can only communicate to this actor via this actor reference. OK, and speaking of which, we can go to part four now, which is actually communicating with our actor. So communicate. And the way that we communicate with an actor through its actor reference is by seeing word counter. Exclamation mark, so this is the method that we use and then the message that we want to send say I am learning Arka and it's pretty -- cool. So the exclamation mark is the method that we are invoking. Of course, you know, from the scholar basics that the exclamation mark is just the name of the method. So we can invoke it in a normal dot notation, but we often use the infix notation in practice. So let's see what happens if I run this application. So we have the name of the system, but we haven't actually printed out the result of this receive message, so let's go about printing something. So print line, let's say word count and let's create a message. Say I have received message. Let's control space to turn this into an s interpretative string and let's run this application again and we will see this little print line statement. See, which tells us that the actor has received this sentence and because it has received the sentence, the total words has been incremented with a number of words in it. Now, it may not be apparent from the simple example, but sending the message here is completely a Synchronoss. So let's say I have another word counter here. And let's copy the actor of expression here, let's call this another award counter and let's send another message to another war counter, let's say a different message. Now, let's rerun this application and see what happens. So we have here the second word counter, the other word counter receives the message, so the second message before the first word counter receives its own message. So AKA sends messages to actors asynchronously. So even in the small example, we see the actual principles in practice. First of all, actors are uniquely identified. There are no two actors with the same name under the same actor system. If I tried to give the same name to both of these actors and if I run this application again, I'm going to get a very nice seductress. So actor name would counter is not unique. So that's one. Secondly, actors are fully encapsulated. You cannot poke at their data, you cannot call their methods, and you cannot even instantiate the actor classes by hand. So if I am very naive and try to instantiate a word count actor myself and if I run this, I'm going to get another very nice stuck tracing actor initialization exception. You cannot create an instance of word count actor explicitly using the constructor new, so you cannot do that by hand. You have to use the actor of factory method in the actor system. So actors are actually fully encapsulated. And the only way that you can communicate with an actor is by sending messages via the exclamation method. The exclamation method is also known as tell. And every actor has internal data and behavior, and the behavior is this method receive, which returns an instance of partial function from any two unit. This is the type that Akka will use. This is also aliased by the type receive, which is exactly the same thing. Now, before I close this lecture, let me address a common question. And the question is, how do we instantiate actors with constructor arguments? Because if we define plain classes, for example, person with a name, which is a string, I can simply instantiate this class by saying new person with named Bob. But the question is and the question that I often get is if this class person somehow extends actor and has some kind of receive method. OK, which we don't really care, we may leave unimplemented, the question is how do we instantiate an actor of type person with a constructor argument? Because if we look at the way that we instantiate actors before that was with actor system, that actor of and then the props and then the type of the actor. But the constructor arguments are not present at all. So how do we do that? The way that we instantiate such an actor is by using props with an argument. And let me show you how to do that. So let's create a Val called person, which is actor system dot actor us, and we can pass in props. And instead of passing the actor type here, we can call the apply method of the props object and we can pass in an actual actor instance. So new person with the name Bob. Now this instantiation with new inside the props apply method is legal, even though we cannot say new ball from the outside. If you say new Bob from the props apply method, you can. So if I run this application again, I should not see that Red Star actress anymore. I'm seeing a different seductress because an implementation is missing for my receive method, so let me add some cases here. Remember, receive is a partial function from Anita unit. So let me add some cases here. So case, let's say this person replies to the message, hi, and just print something to the console. So a print line. Hi, my name is Dollar Name. OK, so I just had control space and the name was injected into this interpolated string. And in case I receive any, anything else I will just not do anything. So if I rerun this application, I shouldn't even see this doctorate's even. All right, let's send a message to this person, actor, just to make sure that the constructor argument was passed correctly. So I'm just going to say person exclamation mark, which is known as tell. So I'm going to say person tell hi. And let's rerun this application and see that the person actor reacts to this message by printing its name to the console. So if we rerun. We see hi, my name is Bob, which is fine, so we created a person actor by passing it a props with an actor instance inside. This is legal, but this is also discouraged. I'm going to show you the best practice, the general best practice for creating props with actor instances, especially for these cases where you want to pass. Passing constructor arguments is to declare a companion object. So we declare a companion object person and we define some methods that return props objects so we can say def props. And we passed the name. And this returns a props object with a new person with that name. This has the advantage that we do not create accurate instances ourselves, but the factory method creates props with accurate instances for us. So instead of props new person, Bob, I'm just going to say person dog props with the name Bob. Of course, if I rerun this application, I'm going to see the exactly same thing. OK, so hi, my name is Bob. So this is the best practice for creating actors with constructor arguments. Define a companion object and define a method that based on some arguments, it creates a props object with an actor instance with your constructor arguments. All right. So in this video, we saw the actor principles in actual code. And we've got a taste of actor systems and actors. Let's move on to the next video and see how actors can send references to one another, how they can reply to messages and talk a little bit about message types and behaviors and then see you there.