2011-12-15 12:05:48 +01:00
|
|
|
|
.. _actors-general:
|
|
|
|
|
|
|
|
|
|
|
|
What is an Actor?
|
|
|
|
|
|
=================
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
The previous section about :ref:`actor-systems` explained how actors form
|
|
|
|
|
|
hierarchies and are the smallest unit when building an application. This
|
|
|
|
|
|
section looks at one such actor in isolation, explaining the concepts you
|
2013-01-22 15:24:15 -05:00
|
|
|
|
encounter while implementing it. For a more in depth reference with all the
|
2011-12-15 12:05:48 +01:00
|
|
|
|
details please refer to :ref:`actors-scala` and :ref:`untyped-actors-java`.
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
An actor is a container for `State`_, `Behavior`_, a `Mailbox`_, `Children`_
|
|
|
|
|
|
and a `Supervisor Strategy`_. All of this is encapsulated behind an `Actor
|
2011-12-15 23:39:39 +01:00
|
|
|
|
Reference`_. Finally, this happens `When an Actor Terminates`_.
|
2011-12-15 12:05:48 +01:00
|
|
|
|
|
|
|
|
|
|
Actor Reference
|
|
|
|
|
|
---------------
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
As detailed below, an actor object needs to be shielded from the outside in
|
|
|
|
|
|
order to benefit from the actor model. Therefore, actors are represented to the
|
|
|
|
|
|
outside using actor references, which are objects that can be passed around
|
|
|
|
|
|
freely and without restriction. This split into inner and outer object enables
|
|
|
|
|
|
transparency for all the desired operations: restarting an actor without
|
|
|
|
|
|
needing to update references elsewhere, placing the actual actor object on
|
|
|
|
|
|
remote hosts, sending messages to actors in completely different applications.
|
|
|
|
|
|
But the most important aspect is that it is not possible to look inside an
|
|
|
|
|
|
actor and get hold of its state from the outside, unless the actor unwisely
|
2011-12-15 12:05:48 +01:00
|
|
|
|
publishes this information itself.
|
|
|
|
|
|
|
|
|
|
|
|
State
|
|
|
|
|
|
-----
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Actor objects will typically contain some variables which reflect possible
|
|
|
|
|
|
states the actor may be in. This can be an explicit state machine (e.g. using
|
2012-01-24 10:45:18 +01:00
|
|
|
|
the :ref:`fsm-scala` module), or it could be a counter, set of listeners,
|
|
|
|
|
|
pending requests, etc. These data are what make an actor valuable, and they
|
|
|
|
|
|
must be protected from corruption by other actors. The good news is that Akka
|
|
|
|
|
|
actors conceptually each have their own light-weight thread, which is
|
|
|
|
|
|
completely shielded from the rest of the system. This means that instead of
|
|
|
|
|
|
having to synchronize access using locks you can just write your actor code
|
|
|
|
|
|
without worrying about concurrency at all.
|
2011-12-15 12:05:48 +01:00
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Behind the scenes Akka will run sets of actors on sets of real threads, where
|
|
|
|
|
|
typically many actors share one thread, and subsequent invocations of one actor
|
|
|
|
|
|
may end up being processed on different threads. Akka ensures that this
|
|
|
|
|
|
implementation detail does not affect the single-threadedness of handling the
|
2011-12-15 12:05:48 +01:00
|
|
|
|
actor’s state.
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Because the internal state is vital to an actor’s operations, having
|
|
|
|
|
|
inconsistent state is fatal. Thus, when the actor fails and is restarted by its
|
|
|
|
|
|
supervisor, the state will be created from scratch, like upon first creating
|
2011-12-15 12:05:48 +01:00
|
|
|
|
the actor. This is to enable the ability of self-healing of the system.
|
|
|
|
|
|
|
|
|
|
|
|
Behavior
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Every time a message is processed, it is matched against the current behavior
|
|
|
|
|
|
of the actor. Behavior means a function which defines the actions to be taken
|
|
|
|
|
|
in reaction to the message at that point in time, say forward a request if the
|
|
|
|
|
|
client is authorized, deny it otherwise. This behavior may change over time,
|
|
|
|
|
|
e.g. because different clients obtain authorization over time, or because the
|
|
|
|
|
|
actor may go into an “out-of-service” mode and later come back. These changes
|
|
|
|
|
|
are achieved by either encoding them in state variables which are read from the
|
|
|
|
|
|
behavior logic, or the function itself may be swapped out at runtime, see the
|
|
|
|
|
|
``become`` and ``unbecome`` operations. However, the initial behavior defined
|
|
|
|
|
|
during construction of the actor object is special in the sense that a restart
|
2011-12-15 12:05:48 +01:00
|
|
|
|
of the actor will reset its behavior to this initial one.
|
|
|
|
|
|
|
|
|
|
|
|
Mailbox
|
|
|
|
|
|
-------
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
An actor’s purpose is the processing of messages, and these messages were sent
|
|
|
|
|
|
to the actor from other actors (or from outside the actor system). The piece
|
|
|
|
|
|
which connects sender and receiver is the actor’s mailbox: each actor has
|
|
|
|
|
|
exactly one mailbox to which all senders enqueue their messages. Enqueuing
|
|
|
|
|
|
happens in the time-order of send operations, which means that messages sent
|
|
|
|
|
|
from different actors may not have a defined order at runtime due to the
|
|
|
|
|
|
apparent randomness of distributing actors across threads. Sending multiple
|
|
|
|
|
|
messages to the same target from the same actor, on the other hand, will
|
2011-12-15 12:05:48 +01:00
|
|
|
|
enqueue them in the same order.
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
There are different mailbox implementations to choose from, the default being a
|
|
|
|
|
|
FIFO: the order of the messages processed by the actor matches the order in
|
|
|
|
|
|
which they were enqueued. This is usually a good default, but applications may
|
|
|
|
|
|
need to prioritize some messages over others. In this case, a priority mailbox
|
|
|
|
|
|
will enqueue not always at the end but at a position as given by the message
|
|
|
|
|
|
priority, which might even be at the front. While using such a queue, the order
|
|
|
|
|
|
of messages processed will naturally be defined by the queue’s algorithm and in
|
2011-12-15 12:05:48 +01:00
|
|
|
|
general not be FIFO.
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
An important feature in which Akka differs from some other actor model
|
|
|
|
|
|
implementations is that the current behavior must always handle the next
|
|
|
|
|
|
dequeued message, there is no scanning the mailbox for the next matching one.
|
|
|
|
|
|
Failure to handle a message will typically be treated as a failure, unless this
|
2011-12-15 12:05:48 +01:00
|
|
|
|
behavior is overridden.
|
|
|
|
|
|
|
|
|
|
|
|
Children
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Each actor is potentially a supervisor: if it creates children for delegating
|
|
|
|
|
|
sub-tasks, it will automatically supervise them. The list of children is
|
|
|
|
|
|
maintained within the actor’s context and the actor has access to it.
|
|
|
|
|
|
Modifications to the list are done by creating (``context.actorOf(...)``) or
|
|
|
|
|
|
stopping (``context.stop(child)``) children and these actions are reflected
|
|
|
|
|
|
immediately. The actual creation and termination actions happen behind the
|
2011-12-15 12:05:48 +01:00
|
|
|
|
scenes in an asynchronous way, so they do not “block” their supervisor.
|
|
|
|
|
|
|
2012-01-23 17:18:49 +01:00
|
|
|
|
Supervisor Strategy
|
|
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
|
|
|
|
The final piece of an actor is its strategy for handling faults of its
|
|
|
|
|
|
children. Fault handling is then done transparently by Akka, applying one
|
|
|
|
|
|
of the strategies described in :ref:`supervision` for each incoming failure.
|
|
|
|
|
|
As this strategy is fundamental to how an actor system is structured, it
|
|
|
|
|
|
cannot be changed once an actor has been created.
|
|
|
|
|
|
|
|
|
|
|
|
Considering that there is only one such strategy for each actor, this means
|
|
|
|
|
|
that if different strategies apply to the various children of an actor, the
|
|
|
|
|
|
children should be grouped beneath intermediate supervisors with matching
|
|
|
|
|
|
strategies, preferring once more the structuring of actor systems according to
|
2011-12-15 12:05:48 +01:00
|
|
|
|
the splitting of tasks into sub-tasks.
|
|
|
|
|
|
|
2011-12-15 16:19:08 +01:00
|
|
|
|
When an Actor Terminates
|
|
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
|
|
|
|
Once an actor terminates, i.e. fails in a way which is not handled by a
|
|
|
|
|
|
restart, stops itself or is stopped by its supervisor, it will free up its
|
|
|
|
|
|
resources, draining all remaining messages from its mailbox into the system’s
|
2012-09-19 00:11:36 +02:00
|
|
|
|
“dead letter mailbox” which will forward them to the EventStream as DeadLetters.
|
|
|
|
|
|
The mailbox is then replaced within the actor reference with a system mailbox,
|
|
|
|
|
|
redirecting all new messages to the EventStream as DeadLetters. This
|
2011-12-15 16:19:08 +01:00
|
|
|
|
is done on a best effort basis, though, so do not rely on it in order to
|
|
|
|
|
|
construct “guaranteed delivery”.
|
|
|
|
|
|
|
|
|
|
|
|
The reason for not just silently dumping the messages was inspired by our
|
|
|
|
|
|
tests: we register the TestEventListener on the event bus to which the dead
|
|
|
|
|
|
letters are forwarded, and that will log a warning for every dead letter
|
|
|
|
|
|
received—this has been very helpful for deciphering test failures more quickly.
|
|
|
|
|
|
It is conceivable that this feature may also be of use for other purposes.
|
|
|
|
|
|
|
|
|
|
|
|
|