Core Concepts
Relevant source files
The following files were used as context for generating this wiki page:
The bbus (bubus) project is an advanced, Pydantic-powered event bus system designed for high-concurrency environments in both Python and TypeScript. It provides a unified runtime for event orchestration, featuring robust locking mechanisms, context propagation, and sophisticated handler completion policies.
At its core, the system facilitates asynchronous communication through strongly-typed event objects that transit through one or more buses. It emphasizes observability via automated parent-child tracking and a centralized middleware architecture for hooks into the event lifecycle.
Sources: TODO_ts.md:5-11, TODO_python.md:12-25
Event Lifecycle and Status
Every event managed by the bus follows a strict state machine from creation to finalization. The system distinguishes between the status of the overall event and the status of individual handler results.
Event Status Transitions
The primary lifecycle of an event is defined by three states: pending, started, and completed. Errors do not exist as a terminal state for the event itself; instead, they are recorded on the specific EventResult objects associated with that event.
The diagram shows the monotonic progression of an event's status.
Sources: TODO_ts.md:12-14, bubus-ts/src/base_event.ts:503-518
Lifecycle Hooks
Middleware and internal monitors hook into these transitions at specific anchors:
- pending: Emitted after the event is enqueued but before the runloop begins processing.
- started: Emitted when the event transitions from pending to started.
- completed: Emitted when the event reaches its terminal state.
Sources: TODO_ts.md:162-170, TODO_python.md:213-217
Architecture and Components
The system architecture is divided into several key components that coordinate event dispatching, execution, and state management.
Key Components
| Component | Responsibility |
|---|---|
| EventBus | Owns orchestration, runloop management, and middleware invocation. |
| BaseEvent | Data structure containing event metadata, payload, and parent/child relationships. |
| EventResult | Tracks the outcome (result or error) of a specific handler for an event. |
| LockManager | Handles concurrency policies (serial, parallel, bus-serial) and semaphores. |
| Middleware | Provides sequential hooks (pending, started, completed) for cross-cutting concerns. |
Sources: TODO_ts.md:31-35, bubus-ts/src/base_event.ts:107-135, TODO_python.md:118-124
Class Relationships
The following diagram illustrates the structural relationship between the core classes:
Class structure showing the hierarchy from the Bus down to individual handler results.
Sources: bubus-ts/src/base_event.ts:107-135, TODO_ts.md:31-40
Concurrency and Execution Control
The system provides fine-grained control over how events and handlers are executed relative to one another.
Concurrency Modes
Concurrency is managed through three primary modes that dictate how the LockManager provides semaphores:
- parallel: No locking; multiple events or handlers run simultaneously.
- serial: Local locking; strictly one at a time within a specific scope (e.g., per event).
- bus-serial / global-serial: Broad locking; only one event processes across the entire bus or global runtime.
Sources: bubus-ts/src/lock_manager.ts:10-25, bubus-ts/src/base_event.ts:311-325
Handler Completion Policies
When multiple handlers are registered for a single event, the event_handler_completion setting determines when the event is considered finished:
- all: The default mode. The event completes only when every registered handler has finished (successfully or with an error).
- first: The event completes as soon as the first handler returns a valid result (non-null/non-undefined). All other in-flight handlers are aborted.
Sources: TODO_ts.md:11-13, bubus-ts/src/base_event.ts:400-415, TODO_python.md:200-205
Parent-Child Tracking and Queue-Jumping
A unique feature of bbus is its ability to automatically track the relationship between events and support "queue-jumping" for dependent events.
Automatic Relationship Linking
When an event is emitted from within the execution context of another handler, the system automatically sets the event_parent_id. This creates an event tree that can be navigated via event_children and event_descendants.
Sources: bubus-ts/src/base_event.ts:335-370, TODO_python.md:73-80
Queue-Jump Logic
If a handler awaits the completion of a child event (e.g., via await event.done()), the system performs a "queue-jump." This bypasses the standard FIFO runloop to prevent deadlocks in serial concurrency modes, ensuring the child event processes immediately across all relevant buses.
Sequence illustrating how a child event jumps the queue when awaited within a handler.
Sources: TODO_ts.md:50-55, bubus-ts/src/base_event.ts:470-485, TODO_python.md:71-78
Error Taxonomy
The runtime enforces a specific error taxonomy to ensure consistent error handling across Python and TypeScript implementations. Terminal handler states are normalized into one of four agreed classes:
| Error Class | Trigger Description |
|---|---|
EventHandlerCancelledError | Handler was in the queue (pending) but cancelled before it could start. |
EventHandlerAbortedError | Handler was already running but was force-stopped (e.g., due to a first() winner or timeout). |
EventHandlerTimeoutError | Handler exceeded its specific event_handler_timeout. |
EventHandlerResultSchemaError | Handler returned a value that failed Zod (TS) or Pydantic (Python) schema validation. |
Sources: TODO_ts.md:15-20, TODO_python.md:16-25, bubus-ts/src/base_event.ts:15-20
Timeouts and Monitoring
The system implements nested timeout scopes to prevent hanging processes:
- Event-level Hard Timeout: A total cap on the entire event's lifetime across all handlers.
- Handler-level Timeout: A specific cap for an individual handler.
- Slow Monitor: A non-fatal warning triggered if a handler exceeds a
slow_timeoutthreshold without yet hitting a hard timeout.
Sources: TODO_ts.md:88-95, TODO_python.md:92-98, bubus-ts/src/base_event.ts:284-300
Summary: Core concepts in bbus center on a deterministic state machine for events, managed by a bus that handles complex concurrency and automatic parent-child relationship tracking. This architecture ensures that even complex, nested async workflows remain observable and protected against deadlocks or infinite execution.