Craftsman at Work

I'm Artur Karbone, coding software architect and independent IT consultant and this is my blog about craftsmanship, architecture, distributed systems, management and much more.

Akka.NET: The Terminator Actor

Imagine, if you need to shut down the actor system programmatically, based on some condition, etc.

You can do it either from the actor system or expose this feature via some external REST API for instance. Well, it depends.

But probably you are going to need a standalone actor for this purpose with the only responsibility to terminate the whole actor system and maybe to check whether a caller is granted to trigger the operation.

Let's go ahead and build the actor:

class TerminatorActor : ReceiveActor  
    {
        #region Messages

        public class Terminate
        {

        }

        #endregion

        public TerminatorActor()
        {   
            this.Receive<Terminate>(m =>
            {
                Context.System.Terminate();
            }, m =>
            {               
                //Use Consesus pattern here to make sure that the sender can actually shutdown the system
                return this.Sender.Path.ToString().Contains("SuperHero");

            });
        }
    }

The Receive Method of the actor handles only one message which is an instance of Terminate class. However, the Receive method has two arguments, two lambdas. The first one is pretty straightforward and just terminates the actor system, calling Context.System.Terminate();. Btw, Context.System.ShutDown() has been marked as an obsolete method recently.

The second Lambda is a predicate which takes the message and returns some boolean (true if the Actor can process the message or false otherwise). Here in the predicate, you can do some consensus algorithms (or validations if you will) to check whether the caller is allowed to shutdown the system. In this particular sample a naive Sender.Path check was used for demonstration purposes only.

Ok, It's time to launch the whole thing. Please, pay attention that this sample uses WhenTerminated to wait until the system is terminated instead of AwaitTermination (The last one was marked as an obsolete method now):

 class Program
    {
        static void Main(string[] args)
        {
            AsyncMain().Wait();
        }

        private static async System.Threading.Tasks.Task AsyncMain()
        {
            using (var myActorSystem = ActorSystem.Create("myActorSystem"))
            {
                var terminatorActor = myActorSystem.ActorOf(Props.Create(() => new TerminatorActor()), "terminatorActor");

                //Emulate unhandled message
                terminatorActor.Tell("Terminate this system");

                terminatorActor.Tell(new TerminatorActor.Terminate());

                await myActorSystem.WhenTerminated;

                Console.WriteLine("Actor System has been terminated");
                Console.ReadLine();
            }
        }
    }

Here is a link to GitHub Repository if you want to play with the whole sample.

comments powered by Disqus