In Akka .NET, actors are very lightweight, and you’re encouraged to use lots of them. It’s thus very common to have a type of entity (e.g. stock symbol, event, session, etc), and an actor dedicated to each instance of that entity.
The source code for this article is available at the Gigi Labs BitBucket Repository. The project is called Entity Per Child (instead of Child Per Entity), because somehow it stuck in my head that way!
Let’s take a practical example. You have an application which receives updates for various different stocks listed on the stock exchange; each of these is represented by a symbol (e.g. MSFT represents Microsoft):
public class StockUpdate { public string Symbol { get; } public decimal Price { get; } public StockUpdate(string symbol, decimal price) { this.Symbol = symbol; this.Price = price; } }
Updates are sent to a StockCoordinatorActor (for this example we’ll simulate this by just having the ActorSystem itself send these messages):
using (var actorSystem = ActorSystem.Create("StockActorSystem")) { var props = Props.Create<StockCoordinatorActor>(); var coord = actorSystem.ActorOf(props, "StockCoordinatorActor"); coord.Tell(new StockUpdate("ABC", 1.20m)); coord.Tell(new StockUpdate("XYZ", 0.59m)); coord.Tell(new StockUpdate("ABC", 1.21m)); coord.Tell(new StockUpdate("HBZ", 0.86m)); coord.Tell(new StockUpdate("FUK", 1.20m)); coord.Tell(new StockUpdate("XYZ", 0.57m)); Console.ReadLine(); }
Now, the StockCoordinatorActor will be responsible for spawning a child actor for each symbol, and directing messages concerning that symbol to that child actor. I see a lot of questions about how to store this mapping in a dictionary, but actually, you don’t need to. Actors can easily access information about their children, so you should use that to your advantage:
public class StockCoordinatorActor : ReceiveActor { public StockCoordinatorActor() { this.Receive<StockUpdate>(Handle, null); } private void Handle(StockUpdate update) { var childName = update.Symbol; // check if a child with that name exists var child = Context.Child(childName); // if it doesn't exist, create it if (child == ActorRefs.Nobody) { var props = Props.Create(() => new StockActor(childName)); child = Context.ActorOf(props, childName); } // forward the message to the child actor child.Tell(update.Price); } }
The child actor that handles the message will simply write out the price update in this example:
public class StockActor : ReceiveActor { private string symbol; public StockActor(string symbol) { this.symbol = symbol; this.Receive<decimal>(Handle, null); } private void Handle(decimal price) { Console.WriteLine($"{Context.Self.Path} - {this.symbol}: {price} "); } }
Let’s run this:
I’m writing out the path of the actor that handles the update, to show that these are actually children of the StockCoordinatorActor.
If you’re dealing with a large number of actors, you might want to use a ReceiveTimeout to kill off the child actors after they’ve been idle for a period of time, to keep memory usage within reason. If a new message eventually comes in, the actor will be recreated by the same child creation logic.
This approach is called the Child Per Entity pattern. It’s actually very similar to using a consistent hashing router to assign work to a pool of dedicated actors based on an ID. With Child Per Entity, you have exactly one actor per ID, while with consistent hashing, you get actors handling multiple IDs. Due to the need to map this level of indirection, Child Per Entity is simpler to use for stateful actors.