Intro
While exploring Cloudflare Durable Objects, Actor Model is a term that I never heard before - something that Cloudflare claims simplifies the development of distributed systems. So this post is an attempt to understand what the Actor Model is, how it works, and why it is useful.
Table of Contents
Open Table of Contents
What is the Actor Model?
The Actor Model is a design pattern that reimagines concurrency by breaking away from traditional shared-memory approaches. Rather than wrestling with locks and synchronised access, it structures applications as networks of autonomous entities called actors, each one a self-contained unit with its own internal world.
These entities operate under three fundamental principles:
- They process incoming requests sequentially,
- Guard their internal data from outside interference, and
- Collaborate by dispatching messages that prompt others into action.
This architecture eliminates the chaos of competing processes by ensuring each component works in complete isolation while maintaining clear communication pathways.
The result is a system that sidesteps the typical pitfalls of concurrent programming - no race conditions, no deadlocks, just clean separation of concerns where each piece knows exactly what it’s responsible for and how to ask others for help when needed.
Consider the following diagram that illustrates the Actor Model with four actors, each with its own state and mailbox for incoming messages, following the three principles mentioned above:
graph TD subgraph "Actor System" A["Actor A
State: count: 5"] B["Actor B
State: balance: 100"] C["Actor C
State: queue: [1,2,3]"] D["Actor D
State: status: active"] end subgraph "Message Flow" A -->|"increment(3)"| B B -->|"process(data)"| C C -->|"notify(complete)"| D D -->|"reset()"| A A -->|"query(status)"| D end subgraph "Actor Mailboxes" MA["📬 Mailbox A
Messages queued"] MB["📬 Mailbox B
Processing sequentially"] MC["📬 Mailbox C
One at a time"] MD["📬 Mailbox D
FIFO order"] end A -.-> MA B -.-> MB C -.-> MC D -.-> MD style A fill:#e1f5fe style B fill:#f3e5f5 style C fill:#e8f5e8 style D fill:#fff3e0 style MA color:#fff style MB color:#fff style MC color:#fff style MD color:#fff
The essence of this diagram is that each actor receives messages in its own mailbox and processes them one at a time, ensuring that the internal state of each actor is not directly accessible by others. An example flow of messages could be:
- Actor A sends an
increment(3)
message to Actor B. - Actor B processes this message and sends a
process(data)
message to Actor C. - Actor C then sends a
notify(complete)
message to Actor D. - Actor D responds with a
reset()
message back to Actor A.
This model allows for clear communication and separation of concerns, making it easier to reason about the system’s behaviour.
Here’s a simple TypeScript implementation of an actor that processes messages sequentially, demonstrating the principles of the Actor Model:
class Actor { private mailbox: Message[] = []; private state: any;
constructor(initialState: any): void { this.state = initialState; }
// Process messages sequentially public receive(message: Message): void { this.mailbox.push(message); this.processNext(); }
private processNext(): void { if (this.mailbox.length > 0) { const message = this.mailbox.shift(); this.handleMessage(message); setTimeout(() => this.processNext(), 0); // Simulate async processing } }
private handleMessage(message: Message): void { // Handle the message and update state console.log(`Processing message: ${message.content}`); // Update state based on message this.state = { ...this.state, ...message.data }; }}
Event-Driven Architecture?
Actors taking to each other through messages? Isn’t that just an event-driven architecture? Not quite. While both share similarities in communication mechanism, and facilitate scalability and fault tolerance, Actors are stateful and encapsulate logic whereas event handlers are typically stateless and reactive. In addition, Actors Model typically have direct message passing between actors, whilst event driven systems events are often broadcast to multiple subscribers.
Aspect | Actor Model | Event-Driven Architecture |
---|---|---|
Communication | Actors send asynchronous messages (HTTPS/RPC calls) to each other. | Components emit or listen to events, often via a broker or event bus. |
State Management | Each actor encapsulates its own state and behavior. | and behavior. State is typically externalised, with services reacting to event payloads. |
Concurrency Model | Inherent; each actor can process messages independently. | Concurrency is often managed at the event processing layer or through reactive programming. |
Processing Flow | Message -> Actor -> internal logic/state update -> response. | Event emitted -> 0 or more subscribers react to it. |
Frameworks | Akka, Microsoft Orleans, Cloudflare Durable Objects. | Apache Kafka, RabbitMQ, AWS EventBridge, Node.js (EventEmitter) |
Pattern Focus | Strongly aligns with OOP and distributed computing. | Often used in microservices, real-time systems, or reactive UIs. |
⬇️ Differences | ------- | ------- |
Encapsulation | Actors are stateful and encapsulate logic. | Event handlers are often stateless. |
Routing | Direct message passing to specific actors. | Event broadcast or pub/sub with multiple consumers. |
Granularity | Fine-grained; every actor is a micro-unit. | Typically coarser-grained services or functions. |
Back to Cloudflare Durable Objects
Durable Objects are Cloudflare’s take on actor-based design - running right at the edge, which effectively means they are distributed across Cloudflare’s global network to provide low-latency access so that each actor (Durable Object) can handle requests close to the user.
Each Durable Object:
- Has a globally unique identifier,
- Maintains its own persistent and isolated state,
- Guarantees that only one instance handles messages at a time.
A typical use case for Durable Objects is to manage chat rooms, where each room is represented by a Durable Object that maintains list of participants and chat history, and processes messages (e.g., new messages, user joins/leaves) sequentially.
Where This All Fits
For today’s developers and DevOps engineers, the actor model is more than an academic concept—it’s a practical blueprint for building safe, scalable systems.
- Developers can use it to simplify real-time logic and avoid complex locking mechanisms.
- DevOps teams can benefit from clearer patterns for deploying distributed workloads.
- Cloud practitioners can better model workflows that combine messaging, compute, and persistence in an efficient, fault-tolerant way.
And with tools like Cloudflare Durable Objects, the actor model is no longer something you have to build yourself - it’s ready to use out of the box.
More to Explore
- proto.actor: A cross-platform actor model framework.
- Akka: A toolkit for building concurrent, distributed, and resilient message-driven applications on the JVM.
- Building stateful actor services on AWS
- Cloudflare Durable Objects