Transcript from the "Spawning Actors" Lesson
>> All right, so now let's talk about spawning actors and to do this, we are going to go to our original scratchpad and take a look at our alarm again. Oops So, one thing that comes up is how exactly do you isolate behavior, in a component. And one of the ways that you could do that is by using what's called an actor model.
[00:00:33] And x state exhibits the actor model in its design. So it exhibits both state machines, state charts, and the actor model too. So to describe what the actor model is, I'm just going to draw a diagram over here. An actor is a thing. Like an entity, and so we could call this an actor.
[00:00:55] I know that might not sound very helpful but an actor is something that basically follows a set of rules and with those Those simple set of rules, you could design entire systems. If you're used to back in programming, then microservices very much exhibit this type of architecture. But an actor is something where You can send it in advance, so I'm just going to put advance here.
[00:01:26] An actor is also something that can send in advance to another actor. So if I copy paste this, And of course an actor can send an event back to that actor if it knows about it. The key word here being that the actor has to know About the other actor as well.
[00:01:52] For example, if you want to call someone you need to know their number. If you want to send them an email, you need to know their email address. You can't really just guess it. You have to physically have it in order to communicate with them. An actor can also spawn child actors.
[00:02:11] And it could spawn basically a dynamic amounts of them. And when it spawns it, it already has a reference to that actor so it could send messages to that actor. And that actor can also send messages back to the parents actor as well. And so, if you're coming from Redux or if you want to look at things in term Reacts, a local state versus context, then you could envision these actors as being local private states.
[00:02:44] So as individual stores that could communicate with other stores. Instead of they're just being one global state or one global store. You have these individual stores where the, the both the behavior and the state inside each one of these actors is completely private. So the only way for an actor to read something from another actor is it has to ask it.
[00:03:10] And then the actor has to send it back via an event. The asking is optional. The actor could just you know, send it back and if this seems a little bit strange to you. One really good analogy is making a web request. When you request something to a server, you are sending a request that might have headers might have query parameters.
[00:03:35] Basically that's an event to the server and the server responds to the client. With in-events of its own, you know, so you a client's can't, for example, directly read a database, it has to ask the server, hey, what are all of the, you know all the things all the rows from this database based on my query, and the server could choose whether to respond or not.
[00:04:00] So that's the actor model. In a nutshell. And I highly suggest reading an article called actor model in ten minutes, which describes the actor model, a little bit more in depth but is still pretty clear to understand. So, just as an example, let's take this alarm machine, We have this behavior which can be isolated, but this is an individual alarm.
[00:04:32] If we have more than one alarm, let's, let's do the obvious thing. First. Let's separate this into its own component. So I'm going to have const alarm equals and then we're going to be returning this. But we also want the, all of these values here too. So we have the alarm machine, and then we could have the alarm over here.
[00:05:00] And now we could have multiple alarms. And of course, each one of these components is going to have its own isolated behavior. So if you squint a little bit, this sort of feels like the actor model already accepts, this really has no way of communicating to its parents and it's sort of an abstract ad hoc structure.
[00:05:24] So let's make a const alarms machine. And this is going to be creating a machine. And so, in our context, which you'll remember is the extended state or the potentially dynamic states. We want to represent each one of our alarm actors. Inside here, so, we're gonna say, alarms and we'll just have that be an empty rate for now.
[00:05:52] We could have an initial state of active, doesn't really matter. States active and then On. We're gonna have an event called add alarm. And over here, this is where we're going to, what's called, spawn, a new alarm actor. And added to this context over here. So, we're going to do this in actions, assign.
[00:06:22] And we're going to be assigning to alarms. So Context. Remember, you get both context and events. But in this case, just for this example, we're going to be using context. So our spawned alarm, which I'm just going to call alarm. There's a function that's exported from x state called spawn.
[00:06:47] And so inside of that function, let's see where we are, right over here. Right over here, we could spawn an alarm machine. So, basically this is saying we are spawning an actor which is like this, this entity this special object with the behaviour of alarm machine, and then we could return context alarms can cat that alarm.
[00:07:20] So let's take a look at what is actually returned here. Const send equals use machine and we're going to use that alarms machine. [COUGH] We're also gonna log the state. Okay, so we have a few things here, we also, let's go ahead and add a button, so that we could actually add, an alarm.
[00:07:51] So, Okay. Cool, so when we click Add alarm and we look in the state, we'll see that the context now has one new alarm. Now this alarm is going to be an object right now it's an interpreter but don't worry about that too much. Just realize that this is an actor that has a send method and we could send events to it.
[00:08:24] So it follows the actor model and because this is an interpreted machine. We could use service and use the alarm directly in use service. So let's expand this alarm here and make it take an alarm prop. So instead of use machine, we want to use service and we're gonna pass in that alarm.
[00:08:52] I like prefixing my my services with Ref or actors in general. Because in general, it's a it's a reference to an actor, so it's an actor ref. All right, so over here we have alarm, alarm ref equals, and of course we need to get those from the states.
[00:09:15] So, we're going to do state.context.alarms.map. Where am I? And we are going to return alarm where the alarm breath, is that alarm? And we have to give it a key as well because that's what we are expects. So okay, so right now there are no alarms. But if I click here, now we have a new alarm.
[00:09:45] If I click here, more alarms, and each one of these again has its own individual behavior. So this might look sort of like we're doing a lot here. Were spawning actors and mapping through them and getting the reference. And using use service to reference each one of these alarms.
[00:10:09] But one of the key things here is each one of these alarms can actually communicate back with the parents. So what the parent could do is also, send an event to all of those alarms as well. So let's just demonstrate sending an event from the child to the parent.
[00:10:36] So, the alarm, let's say that we have pending and active and okay. So once we get to the active states so on entry. We're going to send parent and I'm just going to send it an active event. And so this is basically the child telling the parent, hey, guess what, I'm active now.
[00:11:02] Now, of course the parent doesn't really handle that event. So we'll just do it here, active, Actions and let's just do a plain action over here. So context event, we are going to cancel that log received event. All right, so let's test this out. Let's create a couple alarms and when we click one It's going to tell the parents, hey, I'm active and the parents, right now it doesn't do anything with that event.
[00:11:41] It just receives that event and, yeah, so that is spawning actors in a nutshell. You could also spawn just like in invocations, you could spawn promises, you could spawn observables you could spawn call backs. And of course you could spawn machines as well.
>> And David, as you start to nest these machines and you get to more than a couple of layers.
[00:12:11] Then if you wanted if you needed one of the kind of descendant machines to talk to like a top level. You just have to do send parents and parent all the way up or if there's some other mechanism for the broadcasting or?
>> All right, so the question was, if you needed some deep down like descendants child to talk to some higher ancestor.
[00:12:37] Basically let's actually go to the drawing board Strikescale.com. So let's say that we have a system of actors, which is what. Well what is called when you have so many actors will make three levels over here suddenly copy and paste this and put that there. And let's say that we want this actor to somehow communicate, let's see, let's make this even deeper.
[00:13:07] So, we have this actor over here and this actor is basically the roots. Which communicates with this actor and also communicates with this actor. Alright, so I guess what you're trying to say is what if this actor all the way down here wants to somehow communicate with this one.
[00:13:31] So I'm going to, I'll make this just so that you could see. So we want to somehow communicate with that actor. Naturally actors are a hierarchical structure. So doing something like this doesn't really happen nor should it happen. Because you don't want this spaghetti architecture where any arbitrary actor could communicate with any other arbitrary actor.
[00:14:04] This is a modeling problem and there's a few solutions depending on your use case for this. One of those is using what's called an event bus. Now you can simulate an events bus by just having an actor that acts like as a router. It basically receives a message from an actor that says, hey, I wanna send this to this actor.
[00:14:26] Or I want to post this on this topic, if you're coming from sort of a Kafka or event grid background, and other actors could listen to it too. But in general, an actor can only communicate with other actors it has reference to. However, in the actor model, you could send so, actually, let's make this green.
[00:14:52] You could definitely send a reference to an actor through an actor. So let's say that that this is our special actor that we want the other actor to notify as well. So we have this in Well, we'll call this a reference to that actor. Basically, when this actor creates this actor, it could say, by the way, here's a here's an actor you should know about.
[00:15:22] And so we could give that reference to that actor to this actor as well. And so that actor, since it has a reference to that, it could send an event to that directly. And yeah, so you could do that you could also do in the event Bus sort of way.
[00:15:41] Where this basically is the Event Bus and this might send it to somewhere else depending on what it has reference to. It's sort of an advanced modeling concepts. Just being able to cross those hierarchical boundaries and it doesn't really It doesn't really manifest itself too often in normal apps, in really complex apps it could definitely do that.
[00:16:08] So in the documentation, I'll definitely add how you could simulate in the Event Bus. You could also go to spectrum.chat/statecharts. And there actually is a topic about using things such as an Event Bus within X state. So, Yeah, should be here somewhere but, Yeah, that's definitely a big topic and I could spend a couple of hours talking about just that, but it depends on how you model your system.
[00:16:41] And the beauty about this, is that the answer for this would be the exact same answer for, let's say, how you would do it in sort of a micro service environment. It's an architecture question basically, so, Any other questions?
>> Yeah, this is kind of an aside. Do you have any materials or references or things like that that you think are particularly good for getting better at doing this kind of modeling or this kind of architecture?
>> So the question was, what reference material is there for just learning how to architect actor model based applications better. And honestly, there's a lot of books on it. One of my favorite ones that I read was something applied reactive modeling with Akka, or something like that, reactive modeling Akka.
[00:17:56] Akka, by the way, is a very popular actor model of framework for Java and Scala. So obviously not for Java scripts, they have a .net version Whatever the book is called. But yeah, honestly, I would highly recommend reading books on Akka just because even if you don't do Akka there is a lot of patterns and best practices like this book shows you for doing the actor model in practice.
[00:18:33] And the more you learn about the actor model, the more you see just how many places it actually applies to in the front end. And I think I would say most of actor model usage is in the back end. So, yeah, it's definitely a useful way of thinking for the front end as well.
[00:18:52] So any of the Akka books really.
>> Are there any open source or other larger scale projects that you can point to that we could look at for a reference on best practices and things? Cuz most of all the exercises and tutorials are kind of these smallish kind of like toy projects.
[00:19:11] And so, yeah, that's my question.
>> Yeah, so the question was about are there any exercises or examples you could look for in terms of architecture? And so again what I really like looking at is just if you search like Akka patterns then there's a lot of examples.
[00:19:32] And also a few books like good actor design, applied Akka patterns. And also, let's do akka examples. I think there's actually a repo with a lot of example projects that you could look at. Now, Akka model is a bit of a learning curve. Definitely not as much as state charts.
[00:19:55] But you could generally get the gist of what's happening even if you don't understand, or you're not familiar too much with the language involved. Just by looking at what is being spawned, what events are being sent to other events, and things like that. Another good way to practice, personally, instead of just reading or looking at examples, is by practicing what's called making sequence diagrams.
[00:20:27] So, [COUGH] if you're not familiar with sequence diagrams, sequence diagrams are a way of representing how different actors communicate with each other. So for example over here, this is not a very good sequence diagram, I'll show you something else. Here we go, here's a sequence diagram. So you can see over here that we have these actors at the top such as Game Deck, Player 1, Player 2, and they're sending events to each other.
[00:21:01] So learning how a sequence diagram works, and just the notation for it. That's going to make you a lot better at designing actor model based applications as well. Just practicing by doing that. So you don't even need to do the actor model, or code the actor model in your code.
[00:21:22] It's just a very good practice for when you're talking about business logic just draw it out. And draw it out with your state machines as well. So, that's another point too, a state machine describes the behavior of one actor. An actor model system describes the behavior of how actors talk to each other.
[00:21:46] So that's the difference right there.