Using the Actor Model and Akka.NET for IoT Systems

In additional to cloud-based offerings such as Microsoft’s Azure IoT Suite, it’s also possible to create representations of Internet of Things devices using the Actor Model and Akka.NET. For example, in addition to hosting an Akka.NET actor system in the cloud, you can also have them running on-premises; for example you may have an actor system monitoring an underground railway network for a city. In this case you may already have the infrastructure in place and decide that hosting in the cloud is unnecessary or risky, and deploy to servers geographically close to the underground with some disaster recovery/backup servers located elsewhere.

The Actor Model is a good fit for IoT scenarios due to the inherent concurrency controls, fault-tolerance, and performance/scalability. Akka.NET is a “toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven applications on .NET & Mono”[1].

In the Actor Model, the smallest unit of computation is the actor. An actor can receive messages from other actors, perform computations, manage their state, and send messages to other actors.

For IoT scenarios, actors can model the system in a number of ways. For example, for every physical device in the real world there can be an actor instance to represent that device. This means you may have many actor instances, one for each physical device. When a sensor registers a new reading (temperature, proximity, pressure, etc.) this sensor can communicate with the actor responsible for it, the actor receives a message and can update its internal state to represent the latest reading. The actor representing the device can also respond to another type of message to access the last updated value. The device actor may also be responsible for sending messages to the physical device to update it’s configuration (for example) or this functionality may be broken down into its own actor definition depending on the exact requirements. The device actor may communicate with another actor that is purely responsible for handling the network interfacing required to communicate with devices. In this way if the “network actor” crashed and restarts the actors representing the device don’t crash and lose their state.

Groups of “device actors” can created with the supervision hierarchy that the Actor Model provides to protect groups of actors/devices from crashing other groups of actors/devices. These hierarchies can also provide device management semantics such as the registering of a new device that has just come online. Actors can also represent “abstract” concepts such as the creation of a dedicated actor to perform querying of groups of actors.

To learn more about using Akka.NET with IoT scenarios, check out my Representing IoT Systems with the Actor Model and Akka.NET Pluralsight course.

You can start watching with a Pluralsight free trial.

SHARE:

Persistent Actors in Akka.NET

By default, actors in Akka.NET lose their internal state when they are restarted, for example due to an internal actor error or a system crash.

Akka.Persistence adds additional functionality to enable the storing and restoring of actor state.

There are 2 main persistence concepts: journal storage and snapshot storage.

The Journal

As messages are received by an actor, they may cause some change in the internal actor state. Using Akka Persistence, these messages can be saved in one of a number of configurable journal stores such as SQL Server. When the actor restarts, the messages from the configured journal store are retrieved and “replayed” by the actor. The messages from the journal store will be replayed in the same order as they were originally received by the actor. This in effect rebuilds the actor state one message at a time, each replayed message changing actor state. Once all messages from the journal store have been replayed, the actor state will be equal to what it was before it restarted; it can now process new messages sent to it.

Snapshots

Snapshots are an optional addition on top of the journal store. If an actor has too many messages being replayed from the journal store, and this is causing a performance problem, snapshots can be implemented.

A snapshot, as its name suggests, is a picture of the actor’s state at a given point in time. Snapshots can be created in actor code whenever it is deemed appropriate, for example after every 50 messages have been processed.

Snapshots can improve actor recovery speeds because only those messages stored in the journal since the last snapshot was created need to be replayed. For example, an actor has received 60 messages and a snapshot was created on the 50th message. On restart, Akka.NET notices that a snapshot was created after the 50th message; this snapshot will be loaded into the actor’s state. Now only 10 messages need to be individually replayed (messages 51-60), rather than all 60 messages individually.

To learn more about Akka.Persistence, check out my Akka.NET Persistence Fundamentals Pluralsight course or the Akka.NET documentation.

You can start watching with a Pluralsight free trial.

SHARE:

Testing Akka.NET Actor Systems

My new Pluralsight course Akka.NET Testing Fundamentals is now available.

Testing actor system brings a number of additional considerations over and above the concepts of traditional object oriented unit/integration testing.

While some additional testing support is required, for example as provided by Akka.NET’s TestKit, concepts such as “unit” and “integration” do translate to the testing of actors. For example a “unit” test becomes a test of the behaviour of a single actor in isolation and an “integration” test may involve multiple actors being testing together.

Just as with traditional OO testing where object dependencies can be mocked, so to with actor tests. For example, TestKit provides a number of pre-built mock actors that can be used if the actor(s) being tested need to be isolated. The simplest of these pre-built mock actors is the BlackHoleActor that will simply and silently accept any message sent to it and “swallow” the message. The EchoActor is another pre-built mock actor that will echo any message sent to it back into the test actor system instance as well as optionally back to the sending actor. The TestProbe pre-built mock actor is a more generalised mock actor and can be used in a number of useful ways.

To get access to the benefits of the actor testing infrastructure, the test class inherits from the TestKit base class. By doing this we get access to an automatically created actor system instance into which we can instantiate the actor(s) that need testing.

When testing an actor, it can be treated as a black or white box. A black box test would involve sending a message to the actor and examining (and asserting on) response message(s). Utilising TestKit we can also write white box actor tests where we can get access to the “internal” actor state directly and make asserts on this internal state.

If you’re new to the Actor Model or Akka.NET, check out the docs or my introductory Pluralsight course: Building Concurrent Applications with the Actor Model in Akka.NET.

You can start watching with a Pluralsight free trial.

SHARE:

30 Pluralsight Courses

My new Pluralsight course Stateful Reactive Concurrent SPAs with SignalR and Akka.NET was just published, this brings my total number of courses to 30.

I’ve always loved teaching and sharing and being a Pluralsight author is a great way to continue to do this.

I’d also like to take a moment to say a thankyou to everyone that’s watched my courses and for all the kind words. Thank you.

SHARE:

Improving Message Throughput in Akka.NET with Routers

One of the things I cover in my new Pluralsight course is the awesome feature of routers in Akka.NET.

Routers, with very little code/config change, allow us to spread messages across multiple instances of actors. This means we can process messages concurrently and thus improve the overall throughput of messages in the actor system.

Routers distribute message to a set of actor instance “routees”.

Router Types

Routers can be grouped into two categories: Group routers and Pool routers.

Group routers distribute messages to actors that have already been created in the actor system, this means that a Group router does not supervise its routees.

A Pool router on the other hand does create and supervise its routees.

Routing Strategies

Both Pool and Group routers use routing strategies to determine which routee(s) a message should be routed to. Not all routing strategies are available in both Group and Pool routers.

One of the routing strategies is the Round-Robin strategy. This strategy will route incoming messages in turn to each routee in order, then return back to the first routee and continue around all routees.

An Example

As an example, consider the following console application that simulates some work being done with a Thread.Sleep(200).

using System;
using System.Diagnostics;
using System.Threading;
using Akka.Actor;

namespace ConsoleApplication1
{
    public class CompletedSomeWorkMessage
    {
    }

    public class DoSomeWorkMessage
    {
        public DoSomeWorkMessage(int workItem)
        {
            WorkItem = workItem;
        }

        public int WorkItem { get; private set; }
    }

    public class WorkerActor : ReceiveActor
    {
        private readonly IActorRef _counterActorRef;

        public WorkerActor(IActorRef counterActorRef)
        {
            _counterActorRef = counterActorRef;

            Receive<DoSomeWorkMessage>(
                message =>
                {
                    Console.WriteLine("Working on {0}", message.WorkItem);

                    // simulate some work
                    Thread.Sleep(200);

                    _counterActorRef.Tell(new CompletedSomeWorkMessage());
                });
        }
    }


    public class WorkCounterActor : ReceiveActor
    {
        private int _workLeft;

        public WorkCounterActor(int workToBeDone)
        {
            _workLeft = workToBeDone;

            Receive<CompletedSomeWorkMessage>(
                message =>
                {
                    _workLeft--;

                    if (_workLeft == 0)
                    {
                        // all work is done so shutdown actor system
                        Context.System.Shutdown();
                    }
                });
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {          
            const int totalWorkToBeDone = 20;

            var system = ActorSystem.Create("MySystem");
            var counter = system.ActorOf(Props.Create(() => new WorkCounterActor(totalWorkToBeDone)));
            var worker = system.ActorOf(Props.Create(() => new WorkerActor(counter)));


            var timeTaken = Stopwatch.StartNew();

            for (int i = 1; i <= totalWorkToBeDone; i++)
            {
                worker.Tell(new DoSomeWorkMessage(i));
            }

            system.AwaitTermination();

            timeTaken.Stop();


            Console.WriteLine("Took {0}ms", timeTaken.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}

Running this application results in the following screenshot:

Akka.NET console application screenshot with no router

Notice in the preceding screenshot that to process 20 work items took about 4 seconds.

We can increase the concurrency in the system by adding a Round Robin Pool router.

The following modified code shows the creation of 5 worker actors as part of a pool.

var worker = system.ActorOf(Props.Create(() => new WorkerActor(counter)).WithRouter(new RoundRobinPool(5)));

Now when we execute worker.Tell(new DoSomeWorkMessage(i)) the message will be routed to one of five automatically created WorkerActor instances.

Running the program now results in an execution time of about 1.5 seconds rather than the non-router version that took about 4 seconds.

Akka.NET console application screenshot with a round robin router

To learn more about the different types of routers and other ways to improve message throughput check out my Pluralsight course: Improving Message Throughput in Akka.NET or check out the Akka.NET documentation.

You can start watching with a Pluralsight free trial.

SHARE:

Using Predicates in Akka.NET Receive Actors

When using the Receive actor API in Akka.NET, we can take advantage of overloads of the Receive method that allow us to specify predicates.

A message will now be handled if it is of the correct type and the predicate is met.

Take the following actor that sends emails with a different message if a customer is “high value”:

class WelcomeEmailSender : ReceiveActor
{
    public WelcomeEmailSender()
    {
        Receive<SendNewCustomerWelcomeEmail>(message => HandleMessage(message));
    }

    private void HandleMessage(SendNewCustomerWelcomeEmail message)
    {            
        if (message.IsHighValueCustomer)
        {
            SendEmail("Dear high value customer...", message.EmailAddress);
        }
        else
        {
            SendEmail("Yo! ...", message.EmailAddress);
        }
    }

    private void SendEmail(string greeting, string emailAddress)
    {
        Console.WriteLine("{0} to {1}", greeting, emailAddress);
    }
}

In the preceding code, the if statement is deciding what action is taken – the welcome message to be sent.

Using an overload of the receive method, we can add a predicate that replaces this if statement:

class WelcomeEmailSender2 : ReceiveActor
{
    public WelcomeEmailSender2()
    {
        Receive<SendNewCustomerWelcomeEmail>(
            message =>
            {
                SendEmail("Dear high value customer...", message.EmailAddress);
            },
            handleIf => handleIf.IsHighValueCustomer);

        Receive<SendNewCustomerWelcomeEmail>(
            message =>
            {
                SendEmail("Yo! ...", message.EmailAddress);
            }, 
            handleIf => handleIf.IsHighValueCustomer == false);
    }

    private void SendEmail(string greeting, string emailAddress)
    {
        Console.WriteLine("{0} to {1}", greeting, emailAddress);
    }
}

In the preceding code the predicate (represented by the lambda: handleIf => handleIf.IsHighValueCustomer) replaces the if.

In these example we only have two possible predicates because we are looking at the boolean “IsHighValueCustomer”. The following code shows predicates being defined for non-boolean (string) values:

class SomeActor : ReceiveActor
{
    public SomeActor()
    {
        Receive<string>(message => Console.WriteLine("Knock knock..."), handleIfMessage => handleIfMessage.Equals("Tell me a joke"));
        Receive<string>(message => Console.WriteLine("Hello There!"), handleIfMessage => handleIfMessage.Equals("Say Hi"));
        Receive<string>(message => Console.WriteLine("Woof"), handleIfMessage => handleIfMessage.Equals("Bark like a dog"));
    }
}

If we were to send this actor the following messages they would be received and handled:

IActorRef someActor = actorSystem.ActorOf<SomeActor>("Some");

someActor.Tell("Tell me a joke");
someActor.Tell("Say Hi");
someActor.Tell("Bark like a dog");

However, the following would not be received as it has no matching predicate (even though the message is still of type string):

someActor.Tell("Say bye");

To learn more about Akka.NET, check out the docs or my Pluralsight courses: Building Concurrent Applications with the Actor Model in Akka.NET and Implementing Logging and Dependency Injection in Akka.NET.

You can start watching with a Pluralsight free trial.

SHARE:

New Pluralsight Course: Implementing Logging and Dependency Injection in Akka.NET

If you’ve already watched my Akka.NET fundamentals Pluralsight course and want to learn more about using DI and logging, check out my new Implementing Logging and Dependency Injection in Akka.NET course.

You can start watching with a Pluralsight free trial.

Course Description

Akka.NET makes building concurrent and distributed applications easier. As with other architectures, Akka.NET based systems need effective logging for the monitoring and diagnosing of systems when deployed to production. Just because we use Akka.NET to get the benefits of the Actor Model, it doesn’t mean that best practices for object construction and dependencies such as dependency injection should be ignored. By the end of the course, you’ll understand how to implement effective logging in your Akka.NET system and how to use dependency injection to ensure the services your actors depend on are still provided in a loosely coupled and configurable way.

SHARE:

Switchable Actor Behaviour in Akka.NET

One of the things that actors can do is change their behaviour in response to an incoming message. This doesn’t however mean that we end up with a single “god actor” that has too many responsibilities. Whilst this may also seem like a potentially dangerous thing to do it is actually a very poweful concept. Because an actor instance only processes one message at a time, we don’t have to worry about this behaviour switch affecting the currently processing message, in fact the change in behaviour applies to the next message processed.

There’s a number of benefits to using switchable behaviours including the potential reduction/simplification of the amount of code we need to write and the ability for our brains to conceptualize what the the actor does more readily.

As an example, consider the following code that represents an actor that can respond in one of two ways to an incoming message depending on its current (boolean) state:

class LightSwitchActor : ReceiveActor
{
    private bool _isTurnedOn;
    public LightSwitchActor()
    {
        Receive<FlipTheSwitchMessage>(message => HandleMessage(message));
    }

    private void HandleMessage(FlipTheSwitchMessage message)
    {
        if (_isTurnedOn)
        {
            // do some processing when currently turned on and message received

            // flip the switch
            _isTurnedOn = false;
        }
        else
        {
            // do some processing when currently turned off and message received

            // flip the switch
            _isTurnedOn = true;
        }
    }
}

In the preceding code, the state of the boolean field _isTurnedOn determines how the actor behaves in response to an incoming FlipTheSwitchMessage.

This actor could be refactored so that the isTurnedOn field is removed and the different behavioural states become more explicit:

class LightSwitchBehaviourActor : ReceiveActor
{
    public LightSwitchBehaviourActor()
    {
        TurnedOff();   
    }


    private void TurnedOn()
    {
        Receive<FlipTheSwitchMessage>(
            message =>
            {
                // do some processing when currently turned on and message received                            

                // flip the switch
                Become(TurnedOff);
            });
    }

    private void TurnedOff()
    {
        Receive<FlipTheSwitchMessage>(
            message =>
            {
                // do some processing when currently turned off and message received                                  

                // flip the switch
                Become(TurnedOn);
            });
    }
}

Note the use of the Become() method which allows us to change how we respond to the next message that gets processed.

Whilst in these simple examples there are only two states (TurnedOn and TurnedOff) an actor could describe a greater number of potentially more complex behaviours.

For more information check out the Akka.NET docs or my Pluralsight course: Building Concurrent Applications with the Actor Model in Akka.NET.

You can start watching with a Pluralsight free trial.

SHARE:

Actor Models Come to .NET Developers with Akka.NET

Akka.NET is a port of the Java/Scala Akka framework.

In some ways, the emergence of Akka.NET could be seen as .NET truly “coming of age” - in the sense that other .NET technologies for building web, phone, services, apps etc. are great whereas the distributed .NET story has not been as fully realised – until now with Akka.NET and also Orleans.

In Akka.NET there are two primary constructs: actors and messages.

Actors do work and messages allow actors (and the outside world) to communicate. Actors don’t expose their internal state to other actors, all communication is done with messages.

Messages can be built-in .NET types such as a string or int, or can be custom types containing multiple data items.

Actors perform the work of the system and can essentially do one of four things:

  • Receive and respond to incoming messages
  • Send messages to other actors
  • Create new actors
  • Change behaviour in response to an incoming message

Actors have an incoming mailbox and they process one message at a time, then move onto the next message, and so on. If there are no messages to process the actor sits around being lazy, it only reacts to incoming messages.

The ability of actors to change their behaviour allows the simplification of actor code and also allows the building of finite state machines.

Actors can also be distributed across multiple processes/machines. Akka.NET makes this easier by providing “location transparency”, essentially not having to worry about changing our code just because we want to send a message to an actor in a different process. Akka.NET goes even further and can actually deploy instances of actors automatically to remote machines when they are created by simple modification of config – again requiring no code changes.

Akka.NET also supports the idea that systems can be “self-healing”. Through a hierarchy of supervision, parent actors supervise the child actors that they create. If a child actors errors, the parent supervising it can decide how to handle the failure. We can accept the default supervision strategy or create our own as necessary.

For more information on Akka.NET check out the home page, follow the project on Twitter, or check out my Pluralsight course: Building Concurrent Applications with the Actor Model in Akka.NET.

You can start watching with a Pluralsight free trial.

SHARE: