Skip to main content

actor-model

title: "Actor Model" description: "Isolated actors communicating via async messages—building blocks for concurrent, resilient systems." sidebar_position: 7 hide_title: true

Actor Model

The Actor Model is a mathematical model of concurrent computation that treats "actors" as the universal primitives of a system. An actor is an independent computational entity that communicates with other actors exclusively by exchanging messages. Each actor has a private state, which it can modify only in response to a message, and a mailbox to buffer incoming messages. This model provides a powerful foundation for building highly concurrent, distributed, and fault-tolerant systems.

"Everything is an actor. An actor is a computational entity that, in response to a message it receives, can concurrently: send a finite number of messages to other actors; create a finite number of new actors; designate the behavior to be used for the next message it receives." — Carl Hewitt

Actor System Hierarchy: A supervisor manages worker actors, delegating tasks and handling failures.

Core ideas

  • Isolation (No Shared State): Actors do not share memory. The internal state of an actor is completely encapsulated and can only be modified by the actor itself. This eliminates the need for locks and other complex synchronization mechanisms.
  • Asynchronous Messaging: Communication is done by sending immutable messages to an actor's unique address. Message passing is asynchronous and non-blocking.
  • Mailbox: Each actor has a mailbox (a queue) where incoming messages are stored until the actor is ready to process them. This provides a natural mechanism for backpressure.
  • Behavior: An actor processes one message at a time, and can change its behavior for the next message it processes. This allows for stateful, finite-state-machine-like logic.
  • Supervision: Actors form hierarchies. A parent actor can supervise its children, deciding how to handle their failures (e.g., restart, stop, or escalate). This "let it crash" philosophy is key to building resilient systems.

Examples

These examples demonstrate the basic concept of an actor as an isolated process with a message queue, not a full-fledged, fault-tolerant implementation like Akka or Erlang/OTP.

Sequential call flow for the counter actor example.
actor.py
import asyncio

class CounterActor:
def __init__(self):
self._count = 0
self._mailbox = asyncio.Queue()

async def run(self):
"""The actor's main processing loop."""
while True:
message = await self._mailbox.get()
if message == "get":
print(f"Count is: {self._count}")
elif isinstance(message, int):
self._count += message
self._mailbox.task_done()

def send(self, message):
"""Send a message to the actor's mailbox."""
self._mailbox.put_nowait(message)

async def main():
actor = CounterActor()
# Start the actor's processing loop in the background
asyncio.create_task(actor.run())

actor.send(1)
actor.send(1)
actor.send("get")
await asyncio.sleep(0.1) # Allow time for processing

if __name__ == "__main__":
asyncio.run(main())
When to Use vs. When to Reconsider
When to Use
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Location Transparency
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Mailbox Configuration
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Supervision Strategy
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Message Serialization
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Observability
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.
Security
  1. Highly concurrent systems: Ideal for applications with thousands or millions of concurrent activities, like chat servers, IoT platforms, or gaming backends.
  2. Fault-tolerant, resilient applications: The supervision hierarchy allows for robust, self-healing systems that can gracefully handle failures.
  3. Distributed state management: When you need to manage distributed, mutable state without the complexity of distributed locks or transactions.

Design Review Checklist

  • Is state truly isolated within actors? Is there any 'backdoor' access to shared mutable state?
  • Are all messages immutable?
  • Is the supervision hierarchy clearly defined and tested for various failure scenarios?
  • Is the mailbox strategy (bounded/unbounded, priority) appropriate for the workload?
  • How are message delivery guarantees (at-most-once, at-least-once) handled if required?
  • Is there a plan for observing and debugging actor interactions in a distributed environment?

References

  1. Introduction to Akka (A popular Actor System toolkit) ↗️

  2. Erlang/OTP Design Principles ↗️

  3. The Actor Model in 10 Minutes by Brian Storti ↗️

  4. Hewitt, Meijer and Szyperski: The Actor Model (everything you wanted to know, but were afraid to ask) - A conversation with Carl Hewitt, Erik Meijer, and Clemens Szyperski on the history and impact of the Actor model. Available on YouTube and other platforms.