In this blog posts which will be the first of a multi part series I will cover the fundamentals of Akka.net before diving into coding samples.
What is Akka/Akka.net ?
Akka is an actor-based message-driven runtime for managing concurrency, elasticity and resilience on the JVM with support for both Java and Scala. Akka.net is a port of the library for C# and F#.
Fundamental Principles
In this section we will cover the main components requirement to build a system based on akka.net
The Actor System
Actor is the basic building block in the actor model. Akka provides three important actors that are called the guardians.
The /actor is referred to as “The Root Guardian”. This the root actor in the hierarchy, that supervises the /system and /user actors ( The other guardians).
The /system actor also be referred to as “The System Guardian”. This actor handles graceful shutdown of the system and monitor other system level actors under its tree like logging.
The /user actor is the actor referred to as the “The Guardian Actor”. It is the main actor you will use as a developer. All the actors created will fall under this parent. This is where you’ll be spending all your time as a developer.
Actors follow a tree hierarchy. An actor can create a child actor. The child actor can create additional actors and so on.
Actor Supervision
In Akka the parents will supervise their children. When an error occurs all underlying children are stopped and the parent is notified about the error. The parent will then decide which mechanism to choose to handle the error.
The supervisor has a choice of the following four options:
- Resume the subordinate, keeping its accumulated internal state
- Restart the subordinate, clearing out its accumulated internal state
- Stop the subordinate permanently
- Escalate the failure to the next parent in the hierarchy, thereby failing itself
Is is also important to note that the action applied by the parent can be based on one of the following strategies:
One-For-One says that the directive issued by the parent only applies to the failing child actor. It has no effect on the siblings of the failing child. This is the default strategy.
All-For-One says that that the directive issued by the parent applies to the failing child actor and all of its siblings.
Supervision allows the system to heal itself removing the need for code to be defensive, reducing the amount of code one needs to add to make the system stable as server issues will never bubble up to the top of the stack keeping the core nodes at the top stable.
Referencing an Actor
Each Actor has a unique address. This address will be used by other actors to send messages. Messages will then be stored in the mailbox of the actor.
Placement of the actor in the hierarchy tree define its address. Typically defined as the actor path. (i.e. the path is the address)
Life Cycle of an Actor
The following are the 5 stages of the actor life cycle in Akka.NET:
- Starting. Actor is initialising.
- Receiving. The Actor is now available to process messages.
- Stopping. The Actor goes into this state when it is being restarted or stopped. If the Actor is restarted you will be required to save the messages in the Mailbox so they are processed once the actor is restarted. If the Actor is stopped all the messages in the Mailbox will go to the DeadLetters mailbox of the ActorSystem.
- Terminated. The Actor is in a dead state all the messages in the Mailbox will go to the DeadLetter mailbox
- Restarting. The Actor is about to be restarted and go back to the Starting State
Routing
Routing allows transmission of messages to a group of actors. This is achieved through a special type of actor called a Router. The router as opposed to standard actors can process multiple messages at the same time and is purposely built to handle a large volume of messages.
There are two type of Routers
- Pool Routers. Pool router is a router that creates and supervises a number of workers.
- Group Routers. A Group Router as opposed to a Pool Router, does not create or supervise its actors, it just forwards messages to the workers. These type of routers are rarely used due to the fact that an error in the child will not be propagated to the parent, which could make the system unstable.
A Router uses a RoutingStrategy to define the mechanism to distribute the messages across the actors. These are split in two categories Special-case and Load Balancing strategies.
Special-case Routing strategies
- Broadcast. The router will forward the messages it receives to all the actors it handles
- Random. A random actor is picked for each message.
- ConsistentHash. The router forwards messages based on attributes that are present in the message.
Load Balancing strategy
- Round-robin. The router will use round-robin to select the actor.
- Tail-chopping. The router sends a message to a randomly picked actor and after a small pause send the same message to another actor (picked at random). The first reply is used to reply to the actor sending the message.
- ScatterGatherFirstCompleted. The router will send the message to all the actors. The first reply is sent to the original actor making the request, the rest of the replies are discarded.
- SmallestMailbox. This strategy can only used with Pool Routers. The router will send the message to the actor with the smallest mailbox.
- ResizeableRouter. This strategy can only used with Pool Routers. The router will detect the load on its actors and it can expand or contract the number of actors it handles. The amount of messages in mailbox of the actors is used as a measure to determine the load in the system
In the next post we will dive in some code samples.