DomoActors-Py Actor Model Toolkit for Python
Project description
DomoActors-Py
A Production-Ready Actor Model Toolkit for Python
Overview
DomoActors-Py is a sophisticated actor framework for Python that provides:
- Comprehensive Type Hints: Full type annotations with Protocol classes for IDE support and static analysis
- Fault Tolerance: Hierarchical supervision with configurable strategies
- Message-Driven Concurrency: FIFO per-actor mailboxes with async dispatch
- Flexible Addressing: UUIDv7 for distributed systems, numeric for simple scenarios
- Comprehensive Testing: Observable state, await utilities, dead letter listeners
- Zero External Dependencies: Pure Python implementation using only standard library
Project Status
✅ Production Ready - Fully implemented with comprehensive test coverage (197+ tests, 86% coverage)
Complete Feature Set:
- ✅ Core actor model (Actor, Protocol, Stage)
- ✅ Hierarchical supervision (Resume, Restart, Stop, Escalate)
- ✅ Self-messaging patterns with recursive mailbox dispatch
- ✅ Bounded and unbounded mailboxes with overflow policies
- ✅ Lifecycle hooks (before_start, after_stop, before_restart, etc.)
- ✅ Scheduling (one-time and repeating tasks)
- ✅ Dead letters handling
- ✅ Observable state for testing
- ✅ Full parity with DomoActors-TS
Example Applications:
- ✅ Complete banking system with interactive CLI
- ✅ Transaction coordination with retry logic
- ✅ Context-aware error handling
Quick Start
Installation
Install DomoActors-Py from PyPI using pip:
pip install domo-actors
Requirements: Python 3.10 or higher (no external dependencies!)
Alternative: Install from Source
For development or the latest unreleased features:
git clone https://github.com/VaughnVernon/DomoActors-Py.git
cd DomoActors-Py
pip install -e .
Verify Installation
from domo_actors import stage, Actor, Protocol
print("DomoActors-Py installed successfully!")
Basic Example
import asyncio
from domo_actors import Actor, ActorProtocol, Protocol, ProtocolInstantiator
from domo_actors import Definition, stage, Uuid7Address
# 1. Define the protocol interface
class Counter(ActorProtocol):
async def increment(self) -> None: ...
async def get_value(self) -> int: ...
# 2. Implement the actor
class CounterActor(Actor):
def __init__(self):
super().__init__()
self._count = 0
async def increment(self) -> None:
self._count += 1
async def get_value(self) -> int:
return self._count
# 3. Create protocol instantiator
class CounterInstantiator(ProtocolInstantiator):
def instantiate(self, definition: Definition) -> Actor:
return CounterActor()
class CounterProtocol(Protocol):
def type(self) -> str:
return "Counter"
def instantiator(self) -> ProtocolInstantiator:
return CounterInstantiator()
# 4. Use the actor
async def main():
# Create actor (stage() returns singleton instance)
counter: Counter = stage().actor_for(
CounterProtocol(),
Definition("Counter", Uuid7Address(), ())
)
# Use actor
await counter.increment()
await counter.increment()
value = await counter.get_value()
print(f"Count: {value}") # Output: Count: 2
# Cleanup
await stage().close()
if __name__ == "__main__":
asyncio.run(main())
Core Concepts
Actors
Actors are the fundamental unit of computation. They:
- Process messages sequentially through their mailbox
- Maintain private state
- Can create child actors
- Never share state directly
Messages
Messages are asynchronous and delivered via FIFO mailboxes. DomoActors uses a dynamic proxy pattern that automatically converts method calls into messages.
Supervision
Actors are organized in a hierarchy. When an actor fails, its supervisor decides what to do:
- Restart: Create a new instance
- Resume: Continue processing messages
- Stop: Terminate the actor
- Escalate: Pass the decision to the parent supervisor
Lifecycle Hooks
Actors provide lifecycle hooks for customization:
before_start(): Initialize actor statebefore_stop(): Cleanup before terminationbefore_restart(reason): Cleanup before restartafter_restart(): Re-initialize after restart
Features
Dynamic Proxy Pattern
DomoActors uses Python's __getattr__ magic method to implement a dynamic proxy pattern similar to JavaScript's Proxy API:
# Method calls are automatically converted to messages
await actor.do_something(arg1, arg2)
# Behind the scenes:
# 1. Creates a DeferredPromise
# 2. Wraps call in a LocalMessage
# 3. Enqueues in mailbox
# 4. Returns promise to caller
Mailbox Types
ArrayMailbox: Unbounded FIFO queue
from domo_actors import ArrayMailbox
mailbox = ArrayMailbox()
BoundedMailbox: Capacity-limited with overflow policies
from domo_actors import BoundedMailbox, OverflowPolicy
mailbox = BoundedMailbox(
capacity=100,
overflow_policy=OverflowPolicy.DROP_OLDEST
)
Fault Tolerance
Configure supervision strategies:
from domo_actors import DefaultSupervisor, SupervisionStrategy, SupervisionScope
class MySupervisor(DefaultSupervisor):
async def supervision_strategy(self) -> SupervisionStrategy:
return CustomStrategy()
class CustomStrategy(SupervisionStrategy):
def intensity(self) -> int:
return 5 # Allow 5 restarts
def period(self) -> int:
return 10000 # Within 10 seconds
def scope(self) -> SupervisionScope:
return SupervisionScope.ONE # Only failed actor
Scheduling
Schedule tasks using the built-in scheduler:
from datetime import timedelta
from domo_actors import stage
scheduler = stage().scheduler()
# Schedule once
scheduler.schedule_once(
delay=timedelta(seconds=5),
action=lambda: print("Executed!")
)
# Schedule repeated
scheduler.schedule_repeat(
initial_delay=timedelta(seconds=1),
interval=timedelta(seconds=5),
action=lambda: print("Tick!")
)
Testing
DomoActors provides testing utilities:
from domo_actors.actors.testkit import await_assert, await_state_value
async def test_actor():
# Wait for assertion to pass
await await_assert(
lambda: assert_something(),
timeout=2.0
)
# Wait for state value
await await_state_value(
actor,
"status",
"completed",
timeout=2.0
)
Examples
See the examples/ directory for complete examples:
Counter Example
Basic actor creation and message passing demonstrating:
- Protocol definition
- Actor implementation
- Message passing
- Async/await patterns
Bank Example (Production-Grade)
A complete banking system with interactive CLI (examples/bank/bank.py) demonstrating:
Core Features:
- Account management (open, deposit, withdraw)
- Inter-account transfers with 5-phase coordination
- Transaction history with self-messaging pattern
- Exponential backoff retry logic
Advanced Patterns:
- Hierarchical actors: Bank → Account → TransactionHistory
- Three supervisor types: BankSupervisor, AccountSupervisor, TransferSupervisor
- Context-aware error handling: Custom error messages with request details
- Self-messaging: Actors sending messages to themselves for state consistency
- "Let it crash" philosophy: Validation errors handled by supervisors
Run the example:
cd examples/bank
python bank.py
The bank example is functionally equivalent to the TypeScript version, demonstrating full parity between implementations.
Architecture
┌─────────────────────────────────────┐
│ LocalStage │
│ ┌───────────────────────────────┐ │
│ │ PrivateRootActor │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ PublicRootActor │ │ │
│ │ │ ┌──────────┐ │ │ │
│ │ │ │ User │ │ │ │
│ │ │ │ Actors │ │ │ │
│ │ │ └──────────┘ │ │ │
│ │ └─────────────────────┘ │ │
│ └───────────────────────────────┘ │
│ │
│ Directory (Actor Registry) │
│ Scheduler │
│ DeadLetters │
│ Supervisors │
└─────────────────────────────────────┘
Design Principles
- Correctness First: Type-safe interfaces, strict async/await patterns
- Fault Tolerance: Hierarchical supervision
- Developer Productivity: Protocol interfaces, lifecycle hooks, testing utilities
- Zero Dependencies: Pure Python using only standard library
Comparison with TypeScript Version
DomoActors-Py is a faithful port of DomoActors-TS with Python-specific adaptations:
| Feature | TypeScript | Python |
|---|---|---|
| Proxy Pattern | ES6 Proxy API | __getattr__ magic method |
| Async Model | Promises | asyncio Futures |
| Concurrency | Single-threaded event loop (async/await) | Single-threaded event loop (async/await) |
| Type System | Compile-time static typing | Runtime type hints (PEP 484) |
| Type Checking | Built-in (tsc) | Optional tools (mypy, pyright) |
| IDE Support | Full IntelliSense | Full IntelliSense with type hints |
| Stage Access | stage() singleton |
stage() singleton |
| Mailbox Dispatch | Recursive dispatch | Recursive dispatch |
| Self-Messaging | this.selfAs<T>() |
self.self_as(T) |
| Supervision | Hierarchical supervisors | Hierarchical supervisors |
| Collections | Map/Set | dict/set |
| Actor Lifecycle | Hooks (beforeStart, etc.) | Hooks (before_start, etc.) |
Architectural Parity
Both implementations share the same core architecture:
- Actor hierarchy: PrivateRootActor → PublicRootActor → User actors
- Supervision strategies: Resume, Restart, Stop, Escalate
- Message delivery: FIFO per-actor mailboxes
- Address types: UUIDv7 for distributed, numeric for simple scenarios
- Zero external dependencies: Both use only standard library features
Python-Specific Features
- Context managers: Can use
async withfor resource management - Type hints: Comprehensive PEP 484 type annotations throughout the codebase
- Static type checking: Compatible with mypy, pyright, and IDE type checkers
- Protocol classes: Structural typing similar to TypeScript interfaces
- AsyncIO integration: Native asyncio support, works with existing async code
- Testing: pytest-asyncio integration for async test cases
Concurrency Model
DomoActors-Py uses single-threaded async/await, just like JavaScript/TypeScript:
# Single event loop thread
async def actor_method(self):
await self.some_operation() # Yields to event loop
# Continues on same thread
Key Points:
- ✅ Single-threaded event loop (like JavaScript)
- ✅ Cooperative multitasking at
awaitpoints - ✅ No parallelism, only concurrency
- ✅ Actors process messages sequentially
- ✅ Perfect parity with DomoActors-TS behavior
Note: Python does support multi-threading (threading module) and multi-processing (multiprocessing module), but DomoActors-Py uses pure asyncio to maintain identical semantics with the TypeScript version.
Type Hints and Static Analysis
DomoActors-Py includes comprehensive type hints:
# Full type annotations
def actor_for(
self,
protocol: Protocol,
definition: Definition,
parent: Optional[Actor] = None,
supervisor_name: Optional[str] = None
) -> T:
...
# Generic type variables
T = TypeVar('T')
# Protocol classes for structural typing
class Counter(ActorProtocol):
async def increment(self) -> None: ...
async def get_value(self) -> int: ...
Benefits:
- ✅ IDE autocomplete and IntelliSense
- ✅ Catch type errors before runtime with mypy/pyright
- ✅ Self-documenting code
- ✅ Refactoring safety
Check types statically:
mypy domo_actors # Type check the library
Requirements
- Python 3.10 or higher
- No external dependencies for core functionality
pytestandpytest-asynciofor running tests
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Format code
black domo_actors tests examples
# Type check
mypy domo_actors
# Lint
ruff check domo_actors tests examples
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Support
- Issues: https://github.com/VaughnVernon/DomoActors-Py/issues
- Discussions: https://github.com/VaughnVernon/DomoActors-Py/discussions
- Documentation: See
docs/directory
Acknowledgments
DomoActors-Py is inspired by and builds upon concepts from:
- XOOM/Actors (Java actor framework by Vaughn Vernon)
- DomoActors-TS (TypeScript version)
License
GNU Lesser General Public License v3.0 (LGPL-3.0)
See: ./LICENSE.md
Copyright © 2012-2026 Vaughn Vernon. All rights reserved. Copyright © 2012-2026 Kalele, Inc. All rights reserved.
About the Creator and Author
Vaughn Vernon
- Creator of the XOOM Platform
- Books:
- Live and In-Person Training:
- LiveLessons video training:
- Domain-Driven Design Distilled
- Available on the O'Reilly Learning Platform
- Strategic Monoliths and Microservices
- Available on the O'Reilly Learning Platform
- Domain-Driven Design Distilled
- Curator and Editor: Pearson Addison-Wesley Signature Series
- Personal website: https://vaughnvernon.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file domo_actors-1.0.1.tar.gz.
File metadata
- Download URL: domo_actors-1.0.1.tar.gz
- Upload date:
- Size: 39.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
205aa05c09ecce31431c8787a6cc99f45b8d23e897caaee6d854d5c820b81212
|
|
| MD5 |
3c816ba774b685da1b988027b4469508
|
|
| BLAKE2b-256 |
ba320e74f1b21ea573de553294e61bc0e65a281f019ec15c8ef77dc2ab347a49
|
File details
Details for the file domo_actors-1.0.1-py3-none-any.whl.
File metadata
- Download URL: domo_actors-1.0.1-py3-none-any.whl
- Upload date:
- Size: 57.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75b5fc43bc78d50c6a3284665fac2eb2e295f9bf1cdd6792f646b2b42f0f4221
|
|
| MD5 |
200e4c0765058e5a9bf9781f78db269d
|
|
| BLAKE2b-256 |
b5851aa48a310fb0c980354ff461fcaf70ae9a82b17ca73c9b7905a21d5f172c
|