This is the note of the Akka actor concepts. It is based on the Akka General Concepts documents.
Akka actor is a library for developing scalable, resilient ditributed applications. A distributed system may crash, messages get lost and network latency fluctuates. Akka scales to a cluster and provides easy handling of distributed issues such as data consistency and error recovering.
The actor model encapsulates internal states because actors commuicate with each other only via immutable messages and processes messages sequentially in a single thread. There are two types of errors in the actor model: applicaiton error and system error. The actor handles application errors and use supervision to handle system errors.
The suggested main usage: Don’t use actors for concurrency. Instead, use actors for state that requires a permanent repository and use futures for concurrency.
All user-created actors have a common guardian
/user that is created when the
ActorSystem is started. Another guardian is
/system, the system guardian.
A parent uses
ActorContext.spawn() to create a child. When a parent sotps by calling
Behaviors.stopped, all of its children are recursively stopped.
When an actor fails, the failure information is propagated to the supervision strategy defined when its parent spawns it. The default strategy is to stop th echild.
An actor is a container for state, behavior, a mailbox, child actors and a supervisor strategy. An actor has an explicit lifecycle and should be explicitly terminated directly or indirectly by its ancestor. An actor, in addition to its core function of state management, can perform three fundamental actions:
- send a finite number of messages to other actors.
- create a finite number of new actors.
- designate the behavior to be applied to the next message.
An actor is represented by an actor reference thus it is encapsulated, can be restarted and be location transparent. Actor references are typed and only messages with the specified type can be sent to them.
Actor is modeled as a state machine that has both states and behaviors. A behavior is a function that defines the actions for received messages. The behavior may change over time via state encoding or function swapping. The initial behavior is the behavior at start and restart.
Actors conversate by passing a reply-to actor reference in a message. The reply-to actor reference can be a different type of actor other than the sender actor.
Each actor has exactly one mailbox. A mailbox may be a FIFO ro a primarity mailbox. Handling a single message is single-threaded and atomic. However, different message handling may happen in different threads.
Unexpect failures are system errors that is out of control for a actor, therefore actors use one of three types of supervision decoration to deal with a failure: resume, restart and stop. The resume is often used fro actor’s exeception during message processing.
An actor terminates when it fails without a restart strategy, stops itself or is stopped by its supervisor. Remaining messages from the mailbox of a terminated actor are delivered in a best effort approach to the system’s dead leter box.
Actors are organized into a hierarchical structure to manage failures. An actor system is a thread pool to run and manage actors.
Best practices to structure actors are
- For important data, create one actor for each request to simplify state management. This is known as the “Error Kernel Pattern” from Erlang.
- If one actor depends on another actor for certain task, it should watch and act or the other actor’s liveness.
- An actor should have a single responsibility.
- An actor only dependent on its children, not other actors.
- Use immutable messages.
- No shared mutable states among actors.
- Don’t mutate state in different execution context such as a future or ask future callback.
- The top-level actor should not contain much logic and should only be responsible for starting and monitoring other sub systems.
- The actor system manages shared facilities like scheduling services, configuration, logging etc.
- You shouldn’t care about the number of actors and the message order. Each actor only has 300 byte overhead.
Actor Reference and Actor Path
The foremost purpose for actor reference is sending messages to the actor it represents. An actor gets its reference via
ActorContext.self. Other actors get an actor reference by creating actors or by looking up
Receptionist. An actor reference can be local or remote depending on the configuration of the actor system.
An actor path consists of an achor, which identifies the actor system, followed by the concatenation of the path elements, from root guardian to the designated actor. The unique path obtained by following the parental supervision links towards the root guardian is called the logical actor path and is deterministic once the actor system’s configuration is set.
Two actor reference are different if the two actors are not the same incarnation.
ActorPath stays the same for different incarnations of the same actor.
Message Delivery Reliability
Akka messages follow two rules: at-most-once delivery, message ordering per sender-receiver pair.
It is a good practice to log dead letters and check them from time to time. An actor can subscribe
akka.actor.DeadLetter on the event stream. Deal letters are not propagated over the network. To collect all, you need to subscribe one actor per network ndoe and forward them manually.
By default, when constructiing an actor system,
ConfigFactory.load() is called to read configuration from all
application.properties files from the class path root. The
application is specified by
config.resource property. Then the actor system mergers all
reference.conf resources – usually for libraries.
All default configuration are documented in https://doc.akka.io/docs/akka/current/general/configuration-reference.html.