 Okay. Hey, everybody. We've got Aaron right now talking about Aka.net. Take it away, sir. All right. Well, I'm going to go ahead and begin sharing my screen here. All right. Okay. Perfect. Welcome, everyone. So my name is Aaron Standard. I'm one of the co-founders of the Aka.net project and one of the founders of a company called Petabridge. We provide professional support training and consulting for Aka.net. And today we're going to go ahead and introduce Aka.net to everyone who's watching. So we're going to cover when and how to use the actor model. We're going to talk about what it is, why you might want to use it, and how it works. Now the first thing to explain is what is an actor? Well, the first thing to bear in mind about Aka.net is Aka.net is one implementation of the actor model. Specifically, there's been actor model implementations dating back to really Erlang in the late 1980s. But Aka.net's the most popular implementation of it in the common language runtime. Most what we're going to be dealing with today comes from the core Aka Nuget package. That's what defines all of our actor base types, our configuration, the way addresses work in Aka.net, and so forth. But I wanted to cover really briefly what are some of the other things that Aka.net can do. Nope, there's also Aka.remote, which is a Nuget package that allows actors in one process to communicate with remote actors running in another process on the other side of the network. Then there's also Aka.persistence, which gives actors an event-sourced way of persisting and recovering their data from a database. And that's all very abstract, so you don't have to code against any specific database driver or anything else when you're working with them. Then there's Aka.cluster, which is used to construct highly available networks of Aka.net actors. When you have developers using Aka.net to build big real-time server-side applications, Aka.cluster is usually what they're talking about there. And then there's some other fun abstractions built on top of Aka.actors, such as Aka.streams, which is a useful set of tools for building high-performance streaming workflows. And it connects to tools like Apache Kafka and Azure Event Hubs and SignalR and so forth. So I just wanted to give a broad overview of some of the things the Aka.net framework can do. But the most important fundamental unit of work inside Aka.net is an actor. And this is what a very simple actor looks like in Aka.net. The first thing we want to pay attention to is the actor-base type. In this case, we're using what's known as a receive actor. The way actors work in every actor model implementation, but in this case, specifically in Aka.net, is actors work by sending and receiving messages. So an actor will do some processing when it receives a message, and actors can handle different types of messages. In the case of a receive actor in Aka.net, we use this receive statement here to go ahead and define all the different types of messages that this actor can handle. If we receive a message that doesn't match any one of these receives, we'll go ahead and log a warning message saying that we received a message we couldn't handle. And usually that means there might be a bug with your code. Now every time an actor receives a message of type ping, we're going to go ahead and run this function right here, where that ping object, which is going to be p, the value that we feed into this function. We're going to go ahead, and in this case, we're going to log it using the Aka.net built in logging system here. And then we're going to go ahead and send a reply back to the sender, which is a reference to the actor who sent us this message originally. Now normally, you might want to send a reply back right away, but in this case, we're going to use the scheduler to send the reply back on a delay. And the reason is because this code sample that I wrote, and there'll be a link to it at the end of the presentation, has actors pinging messages back and forth. And because actors can process about four to five million messages per second when they're working inside the same process, that would look really unreadable for a human being. So I use the scheduler to go ahead and slow things down a bit so people could see what's going on. But this is fundamentally what an actor is. It's a set of message processing instructions, and optionally, some state the actor can use and can change while it's processing these messages. Now that's not all the code we need to build an Akadana application, though. We have to actually create an instance of this actor first. And we can't just do that by calling new ping actor. The first thing we need to do is create an actor system. You can think of an actor system as the address space in which actors live. So an actor system usually lives, usually there's only one actor system inside a process, and all of the actors communicate via in-memory message passing by default. But some of the other modules in Akadana I introduced earlier, such as Akadot Remote and Akadot Cluster, allow many actor systems in many different processes to talk to each other. And so an actor in process A can talk to an actor in process B using a little TCP connection. The two actor systems keep open to each other. So that's somewhat outside the scope of this presentation. So after we've created our actor system, the next thing we're going to do is create what's called a set of props for an actor. Props define the actor's type, which constructor we're going to use, what those constructor arguments should be, and some additional configuration parameters that we can set. So for instance, one of the things you can do with Akadot Remote is remotely deploy an actor from one process onto another. That's something you can specify in the props for that actor. So the props that we create is going to be fed in to this actor of method here. And we're also going to give this actor a name. Now if you don't provide a name for an actor, Akadonet will randomly pick one for you. And Akadonet guarantees that every single actor inside your actor system will be globally unique, and each one will have its own unique address. So we're going to abstract over that for the time being by using this actor reference that the actor of method returns. The actor reference is the handle we use for actually sending messages to an actor via the tell method right here. We're going to go ahead and tell that actor a new ping message, and we're going to feed in an initial ping count of zero. And that actor is going to receive this asynchronously. And it'll run that ping code that we defined inside the ping actor base class later. So everything in Akadonet is asynchronous by default. This tell method doesn't return a task or anything you can a-wait on. It's doing fire and forget messaging. If you want to do request response style messaging, where you send a message and you get a reply back and you have a task you can a-wait on, we also have another method called ask that you can use for doing just that. But by default, most developers use fire and forget messaging because it's fast and it's simple. So this is kind of the basics of what actors are in Akadonet. Now, a couple of key terms to remember. First is, what's an actor? Well, an actor is a class that can contain some state, and its primary job is determining how to process messages and where to send replies back to. Actors can do anything while they're processing a message. They can write to a database. They can make a web service call. They can write data out to SignalR or Kafka or Azure. It all depends on how you do it. One of the things that we're gonna cover in a couple seconds here is some of the ways people use actors to solve complex real world problems. But an actor is just a unit of work inside Akadonet. An actor reference is how we talk to actors. So you never have access to an actor's state or its properties directly. You have a reference to the actor that you can use to asynchronously send messages to it. So what the actor reference helps us do is it makes an actor's implementation type and its location on the network transparent to us. All that we care about when we're working with another actor is if I send it this input, I should get this type of output or maybe this stream of output back. I don't need to necessarily know how the actor on the other side of that reference does its job. So it gives us a very high degree of decoupling. And the fact that actors are location transparent, meaning I don't even need to know where the actor is. If it's running locally in the same process as me, or running remotely in another process, gives us the ability to scale our back-end actor systems up and down really easily without having to rewrite our code to include all these different addresses and address combinators and that sort of stuff. The actor reference just works and makes all that transparent for us. And that's a really powerful property for building highly available and highly fault tolerant systems. Next is the actor system. This is the local dress space for actors inside a single process. And by default, all actors within one actor system communicate via passing messages in memory using these concurrent Q sort of mailbox structures. But we also have the ability to cluster multiple actor systems together into a highly available network. And that's what Aka.cluster does. And the vast majority of presentations and YouTube videos I've done talk mostly about that. Now, we've introduced a bit of some of the Aka.actor syntax. And we've talked a bit about how we start actors and send the messages. But what are actors actually doing under the hood that makes them interesting? Why are they special and why would I want to use them? Well, the first thing I mentioned, which is probably the simplest thing to get, is that actors run asynchronously. Take actor one and actor two. At the moment, neither one of them has any messages. Therefore, they're just sitting there not doing anything. But when actor one gets a message pushed into its mailbox, it gets woken up and scheduled for execution on top of the .NET thread pool. And this actor, in the course of processing its message, might send a reply to actor two. And actor two, which is also sleep, will also be woken up and will begin processing a message. And actor one might go back to sleep. Now, when an actor is asleep, it's not using any CPU at all. It's just simply not scheduled for execution. If you took a look on a really busy Akadana actor system running in a server-side environment, there might be hundreds of thousands or millions of actors all running at the same time. And this is because actors are really cheap. By default, the Akadana infrastructure uses about one kilobyte of memory per each actor. So we're not talking about very much. Well, most of the time, if you went ahead and did a printout of what the thread pool queue looked like, you'd only see a very small number of actors working at any given millisecond. That's because most actors are processing a small number of messages that pertain to just the entity that they own. There are some actors, like routers, that might be busy all the time. But most of the time, each actor is only doing work somewhat intermittently. And so we have the ability, using tools like Akadana persistence, to create and kill those actors on demand and have them recover their previous state. Or the ability to even move those across the network if you want. Now, some other important actor guarantees, and this is probably the most important one, is that actors can only process one message at a time. Now, if you've heard of the actor model before, you've probably heard that actors are great at handling concurrent programming. Therefore, if actors are serial processors, meaning they go one message at a time, why would they be good at concurrent programming? Well, the answer is this. Because actors can contain internal state inside the actor class you declare, one of the really big implications of actors being serial processors is that actors can only modify that state one event at a time. Meaning that all actor state is always guaranteed to be thread safe at any given time. So you can write concurrent code by having lots of actors that each own their own little bit of state. And all those different pieces of state can be modified concurrently. But because that state can't be exposed or shared directly via a shared data structure like a concurrent queue or concurrent dictionary, that state's always guaranteed to be thread safe with no synchronization mechanisms. And on top of that, actors process their messages in first in, first out order. Otherwise, known as the order in which they were received. So if you want to apply a certain series of transformations to an actor's state in a linear order, all you have to do is send those messages in that same order and that's the order in which the actor will apply them. So this is a very powerful tool for building systems that can do real time stateful processing and so forth. Because actors give us a much simpler model for working with state management than what's available in sort of the base of common language runtime. Now the last thing I wanted to mention about actors is that state is shared, actually I've got another thing after this, I lied, I'm sorry. The other thing I wanted to mention is that state is shared only through messages. If actor B wants to see the latest value for actor A's state, actor B can't access it directly through some property on actor A. Actor B has to send a message to actor A requesting a copy of that state and actor A will make an immutable copy of that state and transfer it into a message which might transfer over the network or it might just move in memory. Depends on where actor B is but the programmer who wrote the code for actor A doesn't need to know that. So actor A copies its state into a message and actor A might actually receive another event that causes it to modify its state but because it's sending an immutable copy of its original state to actor B, actor B receives a copy of actors A's state in the original condition it was in when that actor processed message 1. Now why is this powerful? Well it means that we have the ability to go ahead and share state with lots of different actors. Let's say if you have a thousand actors all asking actor A for a copy of its state, actor A can deliver the current version of its state to all those actors without having to worry about any side effects which is a concurrent programming term. Meaning that if actor A modifies its state after the fact, that won't have any impact on the state that any of those other actors receive. Now if actor B wants to ensure it always receives the most recent copy of actor A's state whenever it changes, you could do that by implementing a publish and subscribe messaging paradigm between actors A and B. And you can do that in as few lines of code as about 10 in aka.net and it doesn't require any external infrastructure, doesn't require a message bus, doesn't require a database that all this happens through actors and actor references. Now this is a big deal from an architectural standpoint but the way actors are organized is in what's called a supervision tree where at the root of our actor system we have this user actor. That's created by aka.net. Underneath the user actor are one or more top level actors. These are the highest level of actor that can be created by an end user of aka.net. And typically they might represent ownership or like an aggregate root over some area of your business domain. And then further we can decompose that domain down into smaller and smaller units through the creation of child actors. So children are considered to be extensions of the parent's domain. Now what's important about this parent-child relationship is that if a child actor fails, and when I say fail I mean it throws an unhandled exception. When a child actor fails, its parent is gonna get a notification about which child failed and why. So it's gonna get all the exception data back. And the parent can then decide what to do with that child. And by default in the actor model we restart actors that fail. We have them reboot to their initial state which is what that prompts class I showed you earlier defines. And the actor will go ahead and resume processing messages in its mailbox from its initial state once again. And when an actor restarts it doesn't lose any of the messages that hadn't processed yet. Those stayed there in its mailbox. So the reason why we have this supervision model is that in practice it's often far more reliable and far easier to have a failing piece of code like an actor simply crash and restart from a well-known safe state than it is to try to have an actor dig itself out of an exception using a bunch of complicated logic in a tri-catch block. That's what's been observed in practice over many decades starting with the early actor model developers and we embrace that in aka.net today because it allows our developers and our users to build self-healing systems that can recover from failures. And parents can do other things than just restart a child when it fails too. We could permanently shut down a child actor or we could treat an exception as a parent actor could essentially assume responsibility for its child's failure and escalate the supervision directive up to its grandparent which we could use to go ahead and create a rolling restart if we wanted. So these are some of the fundamental properties about how actors work. Now I've gone kind of through the how and the what. Let's talk about the why and the when. Why should you use actors? Why might they be an interesting and good architectural choice for your application? What are some of the advantages they give you? Well, a little bit about my background. I started working with actors at my first startup where I would build a large scale real-time marketing automation system and marketing automation is fundamentally a reactive business. Meaning every single time a user was working through one of our customers' websites or apps, we would receive events about things that user was clicking on, like objects they might want to purchase or things they might want to do. And our customers really wanted the ability to say, hey, when this particular combination of events happen, we want to push a notification out to that user that might include something like a coupon for buying a product they were looking at. This is what's called a reactive system where you have the ability to react to events in flight as they are occurring. Actors are perfect for doing this. In fact, this is one of the original motivations for developing aca.net was this very project. We needed the ability to accumulate, stay in memory so we could very quickly react to real-world changes in real-time. I wanted the ability to send a notification to one of my customers' users within seconds, not hours. And you really need a reactive real-time system in order to do that. And this can all be done, by the way, without any expensive infrastructure or database calls. Aca.net is just a library. It can interact with tools like Kafka and databases and so forth, but you don't need any of that to build a system like this fundamentally. Aca.net can do that workload for you. So if you're in a reactive sort of situation where you need the ability to react to changes on the fly, actors might be a really interesting choice for that type of application. Now, my favorite thing that actors can do is they're really good at reducing big problems into small ones. So imagine for a moment, you have a big fire hose of events coming from lots of different sources. So for instance, a lot of users in the aca.net community are doing IoT work, where, and I'm not talking about home automation, I'm talking about industrial IoT, where they're keeping track of thousands of vehicles or they're reading data from really sensitive healthcare devices or so on. Well, if you have this big fire hose of data and you wanna be able to react to changes for each individual device or maybe each individual user, one of the things that actors can help you do really well is break that big fire hose down into a series of small actors that each own one individual device or one individual user. And all those changes to all those users and all those devices and so forth that might be contained inside that big fire hose, each one of those individual actors that owns the state for that device can all update concurrently. So this gives us a really easy to debug and easy to understand model for how we're gonna do all this data processing. So rather than worrying about shared collections or trying to write a bunch of data into a database and then read it back out and do some aggregation on it, we can do this work in memory as data arrives into our system. So actors are really good at this at being able to take a really big problem and partition it down into small, manageable, easily debuggable parts. So some business cases when you might wanna use ACA.net and I've been working at Petabridge for five years now. We've worked with hundreds of companies all around the world and these are some of the really common use cases that I've seen in my day-to-day training and consulting work. First are just typical event-driven applications like chat or workflow systems or customer relationship management tools. Those are all really good fits for ACA.net. Finance is another common sector, doing things like trying to dynamically price an insurance policy or trying to price a trade on an exchange or trying to detect fraud. These are common examples. Gaming is another common one. The original early adopters of ACA.net were largely Unity 3D programmers trying to build sort of a multiplayer game lobby systems and things like that. Analytics and monitoring and marketing automation, those are the spaces I came from. ACA.net is particularly good at doing real-time monitoring and real-time sort of reactive programming to changes in analytic streams you might be looking at. ACA.net's also really good at systems integration. We need to bust events from point A to point B. ACA.net is great at that. In fact, there's lots of microservice architectures that use ACA.net for doing event processing between different domains. And then finally, IoT is probably the biggest segment that's been using ACA.net pretty heavily. It's a good way to model big streams of data you might be getting from a range of devices and ACA.net can help you really manage that and break it down without having to have a huge amount of training and systems programming level work. The ACA.net infrastructure will do most of this for you. And one other important thing I should mention about ACA.net is it's a Swiss Army knife. Not only can you run it in a big back-end server-side environment, but you can also run it on a Xamarin application, running on a mobile phone, in a Unity 3D game, or in a piece of desktop software if you want. ACA.net can scale down to support devices that are small and can scale up to support large server-side environments that are running hundreds or even thousands of nodes. So just to recap why you should use the active model and why you should use ACA.net, first and the most important reason is because it's fun. ACA.net's cool. It'll change the way you look at writing software and it'll give you an exposure to functional programming in a way that's tasteful for people who've done object-oriented programming their whole lives. And if you're an F-sharp programmer, we have great support for it in ACA.net. And ACA.net actors are a natural fit for the type of programming you already do. But then for the business reasons, ACA.net really simplifies state and event management. It makes it so these complicated concurrency problems are in fact simple and easy to work with. ACA.net makes it really easy to break down big problems into small ones. It integrates really well with other technologies you know and love. Most of our demos that we make here at Petterbridge integrate ACA.net with SignalR. And ACA.net can run everywhere. So if you learn it once, you can bring it with you into lots of projects. Now, if you wanna learn more about ACA.net, I've provided some links. The official project site is getACA.net. But if you wanna go ahead and take a self-paced step-by-step course, you can go to learnACA.net. And we also have some links for instance, learning how to use ACA.cluster and Kubernetes. And I have some code samples that put together for this talk today. So I thank you very much and I'll turn it back over to channel nine to take some questions. Perfect, hey we're here, go ahead Robert. Hey Aaron, it's Robert Green here, how are ya? Doing well, thanks. We got a couple questions, I think we have time for. How much complexity would you say this adds to a system? How much complexity do I think ACA.net adds to a system? It depends on where you use it. If you've been in the business of writing your own, let's say socket management and concurrency management infrastructure, ACA.net will actually atomize your code pretty significantly. It'll reduce a lot of complexity out of it. Now on the flip side, if let's say you're building an application that does simple crud for the most part, there is really no need to use ACA.net in that scenario. It's not gonna give you anything that you couldn't get using ASP.net core in that case. So ACA.net, well it's a great tool, you certainly shouldn't try to use it on every possible project. In systems that are event driven or let's say need to be distributed, ACA.net's a good choice and it doesn't add very much in the way of code complexity. The biggest cost to adopting ACA.net is the style of programming is very different from what you've probably experienced if you're coming from a purely object oriented background. So that's probably the biggest cost to it is really the conceptual overhead for ACA.net. There are a couple of questions about debugging. So briefly, what do you say are best practices for debugging here? The best practices for debugging ACA.net. Well, the first thing I would say is you should definitely use the ACA.net test kit. That provides a somewhat synchronous interface for being able to write unit tests for ACA.net actors. I would highly encourage developers to use that. The second thing I'd recommend is you should go ahead and use the ACA.net built-in logging system generously. It captures a lot of context about where an actor was and what it was doing at the time. And then finally, not to hawk a paid product, but Petterbridge has a proprietary tool called Phobos which does end-to-end tracing of ACA.net actor activity, including over the network. And it's gonna be able to very soon do things like trace messages going from ACA.net to a system like SignalR or RabbitMQ or Kafka. And that'll give you sort of a much more end-to-end picture of what was going on when something went wrong. So, wasn't gonna shill Phobos in this talk, but since you asked. I did ask. All right. No, that's great. Aaron, thank you so much for taking the time to share your knowledge and your product and everything. Oh, and thank you so much for making this product for everybody to use and benefit from it. Everybody, we're gonna finishing up here. Where can we find your slides? I will upload them to SlideShare and tweet them out at you in just a moment. Perfect. Thank you so much. All right, everybody, we're gonna get Ed here talking about ASP.net Razor. So, we're gonna go to the slate here. We're gonna mute until we get the call going. So, thank you so much. We'll be right back.