acb 0.32.1
ACB: Asynchronous Component Base
License: BSD-3-CLAUSE
Requires Python: <3.14,>=3.13

<p align="center">
<img src="./images/acb-logo.png" alt="ACB Logo">
</p>

> **ACB Documentation**: [Main](./README.md) | [Core Systems](./acb/README.md) | [Actions](./acb/actions/README.md) | [Adapters](./acb/adapters/README.md)

# <u>A</u>synchronous <u>C</u>omponent <u>B</u>ase (ACB)

[![Code style: crackerjack](https://img.shields.io/badge/code%20style-crackerjack-000042)](https://github.com/lesleslie/crackerjack) [![Python: 3.13+](https://img.shields.io/badge/python-3.13%2B-green)](https://www.python.org/downloads/)

## ACB is being sunsetted and superseded by the [Oneiric](https://github.com/lesleslie/oneiric) project

## What is ACB?

ACB is a comprehensive asynchronous application platform for building production-ready Python applications with enterprise-grade capabilities. It provides a **complete architectural stack** from low-level utilities to high-level orchestration:

- **Foundation Layer**: Self-contained **actions** (utilities) and flexible **adapters** (integrations)
- **Services Layer**: Long-running components with lifecycle management, health monitoring, and metrics
- **Orchestration Layer**: Event-driven messaging (**Events**), background job processing (**Tasks**), and complex workflow management (**Workflows**)
- **Infrastructure Layer**: Dynamic configuration, dependency injection, and resource management

In simpler terms, ACB evolved from a component framework into a **full application platform** that handles everything from data compression to complex multi-step business processes, all with a consistent, type-safe, async-first API.

ACB can be used as a standalone platform or as a foundation for higher-level frameworks. For example, [FastBlocks](https://github.com/lesleslie/fastblocks) builds on ACB to create a web application framework specifically designed for server-side rendered HTMX applications.

## Key Concepts

If you're new to ACB, here are the key concepts to understand:

1. **Actions**: Self-contained utility functions that perform specific tasks like compression, encoding, or hashing. Think of these as your toolbox of helper functions.
1. **Adapters**: Standardized interfaces to external systems like databases, caching, or storage. Adapters let you switch between different implementations (e.g., Redis vs. in-memory cache) without changing your code.
1. **Dependency Injection**: A pattern that automatically provides components to your functions when needed. This eliminates the need to manually create and pass objects around.
1. **Configuration System**: A way to configure your application using YAML files instead of hardcoding values in your code.
1. **Package Registration**: ACB automatically discovers and registers components in your application, reducing boilerplate code.

## Key Features

### Foundation & Infrastructure

- **Modular Architecture**: Mix and match components across all architectural layers
- **Asynchronous First**: Built for high-performance async operations throughout the stack
- **Pluggable Adapters**: Swap implementations without changing your code (20+ adapter categories)
- **Dynamic Discovery**: Convention-based adapter detection and configuration-driven selection
- **Configuration-Driven**: Change behavior through YAML configuration with hot-reloading support
- **Type Safety**: Built on Pydantic with Protocol-based dependency injection for robust typing
- **Performance Optimized**: Streamlined initialization and reduced overhead (0.18.0+)

### Services Layer (v0.20.0+)

- **Enterprise Services**: Production-ready services with lifecycle management and health monitoring
- **Repository Pattern**: Multi-database coordination with Unit of Work pattern and caching integration
- **Validation Services**: Schema validation, input sanitization, and security-focused data processing
- **Performance Services**: Metrics collection, cache optimization, and query performance analysis

### Orchestration Layer (v0.20.0+)

- **Event-Driven Architecture**: Pub-sub messaging with multiple delivery modes and error handling
- **Background Task Processing**: Reliable job queue with priority support, scheduling, and retry mechanisms
- **Workflow Management**: Complex multi-step process orchestration with state persistence
- **Multiple Backends**: Memory, Redis, RabbitMQ, and APScheduler support for flexible deployment

### Integration & AI (v0.23.0+)

- **AI/ML Adapters**: Seamless integration with LLMs, embedding models, and ML serving platforms
- **Real-time Monitoring**: WebSocket-based dashboards and progress tracking

## Table of Contents

- [Key Concepts](#key-concepts)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Architecture Overview](#architecture-overview)
- [Core Components](#core-components)
  - [Actions](#actions)
  - [Adapters](#adapters)
  - [Universal Query Interface](#universal-query-interface)
  - [Services](#services)
  - [Events & Orchestration](#events--orchestration)
  - [Configuration System](#configuration-system)
  - [Dependency Injection](#dependency-injection)
- [Common Patterns](#common-patterns)
- [Use Cases](#use-cases)
- [Built-in Components](#built-in-components)
- [Security Features](#security-features)
- [Basic Monitoring](#basic-monitoring)
- [Debugging](#debugging)
- [Advanced Usage](#advanced-usage)
- [Documentation](#documentation)
- [Acknowledgements](#acknowledgements)
- [License](#license)
- [Projects Using ACB](#projects-using-acb)
- [Contributing](#contributing)

## Installation

Install ACB using [uv](https://docs.astral.sh/uv/):

```bash
uv add acb
```

> **Note**: ACB requires Python 3.13 or later.

### Optional Dependencies

ACB supports various optional dependencies for different adapters and functionality:

| Feature Group | Components | Installation Command |
| -------------------- | --------------------------------------------------------------- | ------------------------------------------------------ |
| Cache | Memory and Redis caching | `uv add acb --group cache` |
| DNS | DNS management (Cloud DNS, Cloudflare, Route53) | `uv add acb --group dns` |
| FTPD | File transfer (FTP, SFTP) | `uv add acb --group ftpd` |
| Monitoring | Error tracking (Sentry, Logfire) | `uv add acb --group monitoring` |
| Requests | HTTP clients (HTTPX, Niquests) | `uv add acb --group requests` |
| Secret | Secret management (Infisical, GCP, Azure, Cloudflare) | `uv add acb --group secret` |
| SMTP | Email sending (Mailgun) | `uv add acb --group smtp` |
| SQL | Database (MySQL, PostgreSQL, SQLite) | `uv add acb --group sql` |
| Storage | File storage (S3, GCS, Azure, local) | `uv add acb --group storage` |
| NoSQL | Document databases (MongoDB, Firestore, Redis-OM) | `uv add acb --group nosql` |
| Vector | Vector databases (DuckDB, Pinecone, Qdrant, Weaviate) | `uv add acb --group vector` |
| Graph | Graph databases (Neo4j, ArangoDB) | `uv add acb --group graph` |
| AI | AI/ML integrations (Anthropic, OpenAI, Gemini, Ollama) | `uv add acb --group ai` |
| Embedding | Embedding models (OpenAI, Sentence Transformers) | `uv add acb --group embedding` |
| Reasoning | Reasoning frameworks (LangChain, LlamaIndex) | `uv add acb --group reasoning` |
| Models | Model frameworks (SQLModel, Pydantic, Redis-OM, msgspec, attrs) | `uv add acb --group models` |
| Logger | Advanced logging (Logly, Structlog) | `uv add acb --group logger` |
| Demo | Demo/example utilities (Faker) | `uv add acb --group demo` |
| Development | Development tools (pytest, ruff, pre-commit) | `uv add acb --group dev` |
| **Composite Groups** | | |
| Minimal | Cache + Requests (essential web stack) | `uv add acb --group minimal` |
| API | Cache + NoSQL + Requests + Monitoring | `uv add acb --group api` |
| Microservice | Cache + Requests + Monitoring + Secret | `uv add acb --group microservice` |
| Web Application | Cache + SQL + Storage + Requests + Monitoring | `uv add acb --group webapp` |
| Web App Plus | Web app + Vector databases | `uv add acb --group webapp-plus` |
| Cloud Native | Web app + DNS + Secret + Monitoring | `uv add acb --group cloud-native` |
| Data Platform | SQL + NoSQL + Storage + Monitoring | `uv add acb --group dataplatform` |
| GCP Stack | GCP-specific adapters (DNS, Secret, NoSQL, Storage) | `uv add acb --group gcp` |
| All Features | All optional dependencies | `uv add acb --group all` |
| **Multiple Groups** | Combine any groups | `uv add acb --group cache --group sql --group storage` |

## Architecture Overview

ACB follows a **layered architecture** with automatic discovery and registration of components. The platform is organized into distinct layers, each building on the previous one to provide increasingly sophisticated capabilities:

```text
┌─────────────────────────────────────────────────────────────┐
│                    APPLICATION LAYER                        │
│              (Your Code Using ACB Platform)                 │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│              INTEGRATION LAYER (v0.23.0+)                   │
│  ┌──────────────────┐           ┌──────────────────┐       │
│  │    AI/ML         │           │   Monitoring     │       │
│  │   Adapters       │           │   Dashboards     │       │
│  └──────────────────┘           └──────────────────┘       │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│            ORCHESTRATION LAYER (v0.20.0+)                   │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│  │   Events     │  │    Tasks     │  │  Workflows   │    │
│  │  (Pub/Sub)   │  │  (Job Queue) │  │  (Process)   │    │
│  └──────────────┘  └──────────────┘  └──────────────┘    │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│              SERVICES LAYER (v0.20.0+)                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│  │  Repository  │  │  Validation  │  │ Performance  │    │
│  │   (Data)     │  │   (Schema)   │  │  (Metrics)   │    │
│  └──────────────┘  └──────────────┘  └──────────────┘    │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│              FOUNDATION LAYER (Core)                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│  │   Actions    │  │   Adapters   │  │   Models     │    │
│  │  (Utilities) │  │ (20+ Types)  │  │ (Universal)  │    │
│  └──────────────┘  └──────────────┘  └──────────────┘    │
└─────────────────────────────────────────────────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────────┐
│            INFRASTRUCTURE LAYER (Core)                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│  │    Config    │  │  Dependency  │  │   Resource   │    │
│  │   (YAML)     │  │  Injection   │  │   Cleanup    │    │
│  └──────────────┘  └──────────────┘  └──────────────┘    │
└─────────────────────────────────────────────────────────────┘
```

### Directory Structure

```text
acb/
├── actions/             # Foundation: Utility functions (compress, encode, hash)
├── adapters/            # Foundation: Integration modules (20+ categories)
│   ├── cache/           # Memory, Redis caching
│   ├── sql/             # MySQL, PostgreSQL, SQLite
│   ├── nosql/           # MongoDB, Firestore, Redis
│   ├── storage/         # S3, GCS, Azure, local file
│   ├── messaging/       # Memory, Redis, RabbitMQ pub-sub
│   ├── queue/           # Memory, Redis, APScheduler task queues
│   ├── ai/              # Anthropic, OpenAI, Gemini, Ollama
│   ├── models/          # Universal query interface
│   └── ...              # 12+ additional categories
├── services/            # Services Layer: Enterprise components
│   ├── repository/      # Data access with Unit of Work pattern
│   ├── validation/      # Schema validation and sanitization
│   ├── performance/     # Metrics and optimization
│   └── _base.py         # ServiceBase for lifecycle management
├── events/              # Orchestration: Event-driven messaging
├── tasks/               # Orchestration: Background job processing
├── workflows/           # Orchestration: Multi-step process management
├── config.py            # Infrastructure: Configuration system
├── depends.py           # Infrastructure: Dependency injection
├── cleanup.py           # Infrastructure: Resource management
└── logger.py            # Infrastructure: Structured logging
```

## Core Components

ACB is structured around these fundamental building blocks:

### Actions

Actions are modular, self-contained utility functions that perform specific tasks. Unlike services, adapters, events, or tasks, actions are not a runtime architectural layer but rather a utility collection of stateless functions available throughout your application.

#### What Are Actions?

Think of actions as a toolbox of utility functions that you can use anywhere in your application. Unlike the architectural layers (Services, Orchestration, Adapters), actions provide simple utility operations without lifecycle management or external system integration.

Key characteristics of actions:

- **Stateless**: Each action is a pure function with no internal state
- **No Lifecycle**: No initialization, configuration, or shutdown required
- **Categorized by Function**: Organized by verb-based categories (compress, encode, hash, etc.)
- **Consistent API**: Similar operations have similar interfaces
- **Cross-Cutting Utility**: Available for use across all architectural layers

#### Available Actions

| Action Category | Description | Implementations |
| ----------------------- | -------------------------- | ------------------------- |
| **Compress/Decompress** | Efficient data compression | gzip, brotli |
| **Encode/Decode** | Data serialization | JSON, YAML, TOML, MsgPack |
| **Hash** | Secure hashing functions | blake3, crc32c, md5 |

**Quick sample**

```python
from acb.actions.compress import compress, decompress
from acb.actions.encode import encode, decode
from acb.actions.hash import hash


async def pipeline(payload: dict[str, str]) -> tuple[str, dict[str, str]]:
    encoded = await encode.json(payload)
    compressed = compress.brotli(encoded, level=3)
    digest = await hash.blake3(compressed)
    restored = await decode.json(decompress.brotli(compressed))
    return digest, restored
```

For the full catalog, see the [Actions README](./acb/actions/README.md).

### Adapters

Adapters provide standardized interfaces to external systems and services. Each adapter category includes a base class that defines the interface and multiple implementations.

Projects built on ACB, like FastBlocks, can extend this adapter system with domain-specific adapters while maintaining compatibility with ACB's core infrastructure.

#### Understanding the Adapter Pattern in ACB

ACB uses **dynamic discovery** with convention-based adapter loading:

1. **Convention-Based Discovery**: Adapters are automatically detected based on directory structure (`acb/adapters/{category}/{implementation}.py`)
1. **Configuration-Driven Selection**: Choose which implementation to use via `settings/adapters.yml`
1. **Lazy Loading**: Adapters are loaded and initialized only when needed
1. **Dependency Injection**: Seamlessly integrated with ACB's dependency system

This means you can switch from memory cache to Redis by changing a single line in your configuration file, without modifying any of your application code - ACB automatically discovers and loads the correct implementation.

#### Key Adapter Categories

| Adapter Category | Description | Implementations |
| ---------------- | --------------------------- | -------------------------------------- |
| **Cache** | Data caching | Memory, Redis |
| **DNS** | Domain name management | Cloud DNS |
| **FTP/SFTP** | File transfer protocols | FTP, SFTP |
| **Logger** | Structured logging | Loguru, structlog |
| **SQL** | Relational databases | MySQL, PostgreSQL, SQLite |
| **NoSQL** | Document & key-value stores | MongoDB, Firestore, Redis |
| **Storage** | File storage | File, Memory, S3, Cloud Storage, Azure |
| **Secret** | Secret management | Infisical, Secret Manager |

**Example: Import once, reuse everywhere**

```python
from acb.adapters import import_adapter
from acb.depends import depends, Inject

Cache = import_adapter("cache")
Storage = import_adapter("storage")


@depends.inject
async def cache_example(
    cache: Inject[Cache],
    storage: Inject[Storage],
) -> None:
    await cache.set("user:123", {"name": "Jill"}, ttl=60)
    user = await cache.get("user:123") or await storage.get("user:123")
    if user:
        await cache.delete("user:123")
```

**Switching Implementations**

To switch from memory cache to Redis, just update your `settings/adapters.yml` file:

```yaml
# Use in-memory cache (good for development)
cache: memory

# OR

# Use Redis cache (good for production)
cache: redis
```

Your application code remains exactly the same!

For more detailed documentation on adapters, see the [Adapters README](./acb/adapters/README.md).

### Universal Query Interface

ACB provides a powerful Universal Query Interface that allows you to write database queries that work consistently across both SQL and NoSQL databases, while maintaining full type safety and supporting multiple query patterns.

#### Key Benefits

- **Database Agnostic**: Write queries that work with MySQL, PostgreSQL, MongoDB, Firestore, and Redis
- **Universal Model Support**: Automatically works with SQLModel, SQLAlchemy, Pydantic, msgspec, attrs, and Redis-OM
- **Intelligent Auto-Detection**: Automatically detects model types - no configuration needed
- **Multiple Query Styles**: Choose between Simple, Repository, Specification, and Advanced patterns
- **Type Safety**: Full generic type support with automatic serialization/deserialization
- **Composable Business Logic**: Build complex rules with the Specification pattern
- **Multi-Framework Applications**: Use different model frameworks in the same application

#### Universal Model Framework Support

ACB's Models adapter automatically detects and works with multiple model frameworks seamlessly:

```python
from sqlmodel import SQLModel, Field
from pydantic import BaseModel
import msgspec
import attrs
from acb.adapters import import_adapter

# Get the models adapter - auto-detects all framework types
Models = import_adapter("models")
models = depends.get(Models)


# SQLModel for SQL databases - automatically detected
class User(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    name: str
    email: str


# SQLAlchemy for traditional ORM - automatically detected
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import DeclarativeBase


class Base(DeclarativeBase):
    pass


class Product(Base):
    __tablename__ = "products"
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    price = Column(Integer)


# Pydantic for API DTOs - automatically detected
class UserCreateRequest(BaseModel):
    name: str
    email: str


# msgspec for high-performance serialization - automatically detected
class UserSession(msgspec.Struct):
    user_id: str
    token: str
    expires_at: int


# attrs for mature applications - automatically detected
@attrs.define
class UserProfile:
    bio: str
    avatar_url: str


# All work with the same universal query interface!
print(models.auto_detect_model_type(User))  # "sqlmodel"
print(models.auto_detect_model_type(Product))  # "sqlalchemy"
print(models.auto_detect_model_type(UserCreateRequest))  # "pydantic"
print(models.auto_detect_model_type(UserSession))  # "msgspec"
print(models.auto_detect_model_type(UserProfile))  # "attrs"

# Get the right adapter automatically
user_adapter = models.get_adapter_for_model(User)  # SQLModelAdapter
product_adapter = models.get_adapter_for_model(Product)  # SQLAlchemyModelAdapter
dto_adapter = models.get_adapter_for_model(UserCreateRequest)  # PydanticModelAdapter
session_adapter = models.get_adapter_for_model(UserSession)  # MsgspecModelAdapter
profile_adapter = models.get_adapter_for_model(UserProfile)  # AttrsModelAdapter
```

**Why This Matters**: You can migrate between frameworks, use different frameworks for different purposes, or gradually adopt new frameworks without rewriting your query logic.

#### Query Patterns

**Simple Query Style** - Active Record-like interface for basic CRUD operations:

```python
from acb.adapters.models._hybrid import ACBQuery
from sqlmodel import SQLModel, Field


class User(SQLModel, table=True):
    id: int = Field(default=None, primary_key=True)
    name: str
    email: str
    active: bool = True


# Setup query interface
query = ACBQuery()

# Simple CRUD operations that work with any database
users = await query.for_model(User).simple.all()
user = await query.for_model(User).simple.find(1)
new_user = await query.for_model(User).simple.create(
    {"name": "John Doe", "email": "john@example.com"}
)
```

**Repository Pattern** - Domain-driven design with built-in caching:

```python
from acb.adapters.models._repository import RepositoryOptions

# Configure repository with caching and audit trails
repo = query.for_model(User).repository(
    RepositoryOptions(
        cache_enabled=True, cache_ttl=300, enable_soft_delete=True, audit_enabled=True
    )
)

# Domain-specific methods
active_users = await repo.find_active()
recent_users = await repo.find_recent(days=7)
```

**Specification Pattern** - Composable business rules:

```python
from acb.adapters.models._specification import field, range_spec

# Create reusable specifications
active_spec = field("active").equals(True)
adult_spec = field("age").greater_than_or_equal(18)
email_spec = field("email").like("%@company.com")

# Combine specifications
company_employees = active_spec & adult_spec & email_spec

# Use across different query styles
users = await query.for_model(User).specification.with_spec(company_employees).all()
```

**Advanced Query Builder** - Full control over query construction:

```python
# Complex queries with method chaining
users = await (
    query.for_model(User)
    .advanced.where("active", True)
    .where_gt("age", 21)
    .where_in("department", ["engineering", "product"])
    .order_by_desc("created_at")
    .limit(10)
    .all()
)
```

#### Database Switching

The same query code works across different databases. Switch implementations by changing your configuration:

```yaml
# Use SQL database (PostgreSQL, MySQL, SQLite)
adapters.yml:
  sql: postgresql

# OR use NoSQL database (MongoDB, Firestore, Redis)
adapters.yml:
  nosql: mongodb
```

Your query code remains identical regardless of the database backend!

#### Hybrid Database Architecture

Use different databases for different models in the same application:

```python
# Users in SQL database
sql_query = ACBQuery(database_adapter_name="sql", model_adapter_name="sqlmodel")
users = await sql_query.for_model(User).simple.all()

# User activity in NoSQL database
nosql_query = ACBQuery(database_adapter_name="nosql", model_adapter_name="pydantic")
activity = await nosql_query.for_model(UserActivity).simple.all()
```

For comprehensive documentation and examples, see the [Models Adapter Documentation](./acb/adapters/models/README.md).

### Services

ACB's Services layer provides a standardized framework for building long-running, stateful components with lifecycle management, health checking, metrics collection, and resource cleanup capabilities. Services extend the ServiceBase class to get consistent patterns for initialization, shutdown, and health monitoring.

#### Key Features

- **Lifecycle Management**: Standardized patterns for service initialization, operation, and graceful shutdown
- **Health Monitoring**: Built-in health checking with customizable health check logic
- **Metrics Collection**: Standardized metrics collection for performance and operational visibility
- **Dependency Injection Integration**: Seamless integration with ACB's dependency injection system
- **Configuration Management**: Standardized settings and configuration patterns
- **Resource Cleanup**: Automatic resource management and cleanup patterns

#### Service Architecture Patterns

ACB uses two main patterns for structuring services:

1. **Simple Services**: Services that directly inherit from ServiceBase for focused functionality
1. **Complex Services**: Services with complex domain logic that use a `_base.py` file pattern to define protocols and abstract interfaces

**Services with Complex Domain Logic** (like repository, validation):

- Use the `_base.py` pattern to define protocols, interfaces, and abstract base classes
- This allows for multiple implementations and clear contracts
- Separate abstract contracts from concrete implementations

**Services with Focused Functionality** (like performance optimizers):

- Direct inheritance from ServiceBase is appropriate
- Less need for complex inheritance hierarchies if functionality is straightforward
- Still follow ServiceBase for consistent lifecycle management

#### Example: Creating a Simple Service

```python
from acb.services._base import ServiceBase, ServiceConfig, ServiceSettings
from acb.depends import depends


class MyCustomService(ServiceBase):
    """A custom service example."""

    def __init__(self):
        service_config = ServiceConfig(
            service_id="my_custom_service",
            name="My Custom Service",
            description="An example custom service",
            priority=50,  # Initialization priority
        )
        settings = ServiceSettings()
        super().__init__(service_config, settings)

    async def _initialize(self) -> None:
        """Service-specific initialization logic."""
        self.logger.info("Initializing my custom service")
        # Add initialization code here

    async def _shutdown(self) -> None:
        """Service-specific shutdown logic."""
        self.logger.info("Shutting down my custom service")
        # Add cleanup code here

    async def _health_check(self) -> dict:
        """Service-specific health check logic."""
        return {"status": "ok", "custom_metric": "value"}


# Usage with dependency injection
@depends.inject
async def use_my_service(my_service: MyCustomService = depends()):
    # Use the service instance
    await my_service.initialize()
    # ... do work ...
    await my_service.shutdown()
```

#### Available Services

| Service Category | Description | Key Features |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------------------ |
| **Repository** | Data access layer with Unit of Work pattern | Multi-database coordination, caching integration, transaction management |
| **Validation** | Data validation with security features | Schema validation, input sanitization, performance monitoring |
| **Performance** | Optimization services | Metrics collection, cache optimization, query optimization |

### Events & Orchestration

ACB's Events, Tasks, and Workflows systems provide comprehensive orchestration capabilities for building complex, event-driven applications with reliable background processing and process management.

#### Events System

The Events system provides pub-sub messaging capabilities with support for event-driven communication between components.

**Key Features:**

- **Event-Driven Architecture**: Support for pub-sub patterns with multiple subscription options
- **Event Types**: Support for different delivery modes (fire-and-forget, at-least-once, exactly-once)
- **Event Handling**: Support for both functional and class-based event handlers
- **Error Handling**: Built-in retry mechanisms and error management
- **Performance**: Optimized for high-throughput event processing

**Example: Using the Events System**

```python
from acb.events import create_event, EventPublisher, event_handler, EventHandlerResult

# Create and publish events
event = create_event("user.created", "user_service", {"user_id": 123})

async with EventPublisher() as publisher:
    await publisher.publish(event)


# Define event handlers
@event_handler("user.created")
async def handle_user_created(event):
    user_id = event.payload["user_id"]
    print(f"Processing user creation for {user_id}")
    return EventHandlerResult(success=True)
```

#### Tasks System

The Tasks system provides reliable background job processing with multiple backend support and advanced scheduling capabilities.

**Key Features:**

- **Multiple Backends**: Support for memory, Redis, and message queue backends
- **Priority Processing**: Support for prioritized task execution
- **Scheduling**: Support for delayed execution and cron-style scheduling
- **Retry Mechanisms**: Configurable retry with exponential backoff
- **Monitoring**: Built-in metrics and monitoring capabilities

**Example: Using the Tasks System**

```python
from acb.tasks import create_task_queue, TaskData, task_handler

# Create a task queue
async with create_task_queue("memory") as queue:
    # Define a task handler
    @task_handler("email_task")
    async def send_email_task(task_data):
        email = task_data.payload["email"]
        # Send email logic here
        return {"sent": True, "email": email}

    # Register handler
    queue.register_handler("email_task", send_email_task)

    # Create and enqueue a task
    task = TaskData(
        task_type="email_task",
        payload={"email": "user@example.com"},
    )
    task_id = await queue.enqueue(task)
```

#### Workflows System

The Workflows system provides orchestration capabilities for managing complex multi-step processes with state management and error handling.

**Key Features:**

- **State Management**: Persistent state tracking for long-running processes
- **Process Orchestration**: Management of complex multi-step operations
- **Error Handling**: Comprehensive error handling and compensation mechanisms
- **Monitoring**: Built-in workflow monitoring and tracking

**Example: Using the Workflows System**

```python
from acb.workflows import WorkflowService

workflow_service = WorkflowService()


# Define and execute workflows with state management
async def execute_complex_process():
    # Workflow execution with state persistence and error handling
    result = await workflow_service.execute_workflow(
        "complex_business_process",
        {"input_data": "value"},
        timeout=3600,  # 1 hour timeout
    )
    return result
```

### Configuration System

ACB's configuration system is built on Pydantic and supports multiple configuration sources:

- **YAML Files**: Environment-specific settings in YAML format
- **Secret Files**: Secure storage of sensitive information
- **Secret Managers**: Integration with external secret management services

#### Where settings live

| File | Purpose |
| ------------------------- | --------------------------------------------------------------------------------------------------------- |
| `settings/app.yaml` | Application-wide metadata (name, domain, platform, feature toggles) |
| `settings/debug.yaml` | Controls debug/trace switches per adapter category |
| `settings/adapters.yaml` | Chooses which implementation backs each adapter category (cache, queue, sql, …) |
| `settings/<adapter>.yaml` | Per-adapter configuration keyed by adapter category (e.g.,`settings/cache.yaml`, `settings/storage.yaml`) |
| `settings/secrets/` | File-based secrets that override any of the above |

ACB always reads `app.yaml`/`debug.yaml` for global settings. Adapter-specific
settings come from two places:

1. **`settings/adapters.yaml`** – select the implementation for each adapter
   category.
1. **`settings/<category>.yaml`** – supply configuration for the selected
   implementation.

Example:

```yaml
# settings/adapters.yaml
cache: redis
storage: s3
queue: apscheduler
```

```yaml
# settings/cache.yaml
cache:
  host: "redis.internal"
  port: 6379
  default_ttl: 900

# settings/queue.yaml
queue:
  job_store_type: postgres
  job_store_url: postgresql+asyncpg://scheduler:pass@db/scheduler
```

If you skip `settings/<category>.yaml`, the adapter falls back to its defaults.
Secrets that power those configs (Redis passwords, API keys, etc.) belong in
`settings/secrets/<name>.yaml` or the configured secret manager so they never
appear in Git.

#### Example: Defining custom settings

```python
from acb.config import Settings
import typing as t
from pydantic import SecretStr


class MyServiceSettings(Settings):
    api_url: str = "https://api.example.com"
    api_version: str = "v1"
    timeout: int = 30
    max_retries: int = 3
    api_key: SecretStr = SecretStr("default-key")  # Automatically handled securely
```

### Dependency Injection

ACB features a simple yet powerful dependency injection system that makes component wiring automatic and testable. Starting in v0.20.0+, ACB uses a **hybrid dependency injection architecture** that matches the pattern to the architectural layer.

#### How Dependency Injection Works in ACB

```
┌─────────────────────┐      ┌─────────────────────┐
│                     │      │                     │
│  Your Application   │      │   ACB Components    │
│                     │      │                     │
└──────────┬──────────┘      └──────────┬──────────┘
           │                            │
           │                            │
           ▼                            ▼
┌─────────────────────────────────────────────────┐
│                                                 │
│             Dependency Registry                 │
│                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────┐  │
│  │   Config    │  │   Cache     │  │ Logger  │  │
│  └─────────────┘  └─────────────┘  └─────────┘  │
│                                                 │
└─────────────────────────────────────────────────┘
                        │
                        │
                        ▼
┌─────────────────────────────────────────────────┐
│                                                 │
│             @depends.inject                     │
│                                                 │
│  Automatically injects dependencies into your   │
│  functions based on type annotations or         │
│  explicit depends() calls                       │
│                                                 │
└─────────────────────────────────────────────────┘
```

#### Protocol-Based vs Concrete Class Dependency Injection (v0.20.0+)

ACB uses different dependency injection patterns for different architectural layers:

| Component Type | DI Pattern | Interface Type | Injection Syntax | Best For |
| -------------- | -------------- | ----------------- | ----------------------------------- | -------------------------------------------------- |
| **Services** | Protocol-based | `ServiceProtocol` | `Inject[RepositoryServiceProtocol]` | Business logic, complex workflows, easy testing |
| **Adapters** | Concrete class | Base class | `Inject[Cache]` | Infrastructure, external systems, shared utilities |
| **Core** | Concrete class | Direct class | `Inject[Config]` | Configuration, logging, foundational components |

**Why Different Patterns?**

- **Services**: Use Protocol-based DI for clean interfaces and easy mocking in tests
- **Adapters**: Use concrete class DI to leverage shared infrastructure (connection pooling, retry logic, cleanup)
- **Core**: Use concrete class DI for stable, foundational components

#### Pattern 1: Protocol-Based DI (Services)

**When to use**: Business logic, complex workflows, testable components

```python
from acb.depends import depends, Inject
from acb.services.protocols import (
    RepositoryServiceProtocol,
    ValidationServiceProtocol,
)


@depends.inject
async def process_order(
    order_id: str,
    repo: Inject[RepositoryServiceProtocol],  # Protocol, not concrete class