Skip to main content

DomoActors-Py Actor Model Toolkit for Python

Project description

DomoActors-Py

A Production-Ready Actor Model Toolkit for Python

License: LGPL-3.0 Python 3.10+ PyPI Test Coverage

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 state
  • before_stop(): Cleanup before termination
  • before_restart(reason): Cleanup before restart
  • after_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

  1. Correctness First: Type-safe interfaces, strict async/await patterns
  2. Fault Tolerance: Hierarchical supervision
  3. Developer Productivity: Protocol interfaces, lifecycle hooks, testing utilities
  4. 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 with for 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 await points
  • ✅ 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
  • pytest and pytest-asyncio for 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:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Support

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

domo_actors-1.0.1.tar.gz (39.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

domo_actors-1.0.1-py3-none-any.whl (57.3 kB view details)

Uploaded Python 3

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

Hashes for domo_actors-1.0.1.tar.gz
Algorithm Hash digest
SHA256 205aa05c09ecce31431c8787a6cc99f45b8d23e897caaee6d854d5c820b81212
MD5 3c816ba774b685da1b988027b4469508
BLAKE2b-256 ba320e74f1b21ea573de553294e61bc0e65a281f019ec15c8ef77dc2ab347a49

See more details on using hashes here.

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

Hashes for domo_actors-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 75b5fc43bc78d50c6a3284665fac2eb2e295f9bf1cdd6792f646b2b42f0f4221
MD5 200e4c0765058e5a9bf9781f78db269d
BLAKE2b-256 b5851aa48a310fb0c980354ff461fcaf70ae9a82b17ca73c9b7905a21d5f172c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page