blackbull.event¶
blackbull.event
¶
Event-driven dispatcher.
Implements the minimal Pub/Sub dispatcher used by BlackBull.on /
BlackBull.intercept. Two delivery modes are supported:
- Interception (
intercept): handlers are awaited in registration order; exceptions propagate to the emitter and abort subsequent interceptors. - Observation (
on): handlers are scheduled as independentasyncio.Tasks (fire-and-forget); exceptions are caught and logged and never reach the emitter or other observers.
Event
dataclass
¶
An immutable message dispatched through EventDispatcher.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The event name (e.g. |
detail |
dict
|
Arbitrary per-event data. |
EventDispatcher
¶
Minimal Pub/Sub dispatcher with split interception/observation paths.
Interception handlers (intercept) are awaited in registration order;
their exceptions propagate to the emitter. Observation handlers (on)
are scheduled via asyncio.create_task (fire-and-forget) and their
exceptions are caught and logged — they never reach the emitter.
Observer tasks are tracked so they can be drained at shutdown via
:meth:aclose. The drain timeout is configured at construction time
(shutdown_timeout); any task still running after the timeout is
logged at WARNING and cancelled.
aclose()
async
¶
Drain pending observer tasks during shutdown.
Waits up to shutdown_timeout seconds (configured at
construction) for all in-flight observer tasks to complete. Any
tasks still running after the timeout are logged at WARNING and
cancelled.
emit(event)
async
¶
Dispatch event to all registered handlers.
Interception handlers are awaited in registration order; their
exceptions propagate. Observation handlers are scheduled as
independent tasks and their exceptions are isolated.
Tasks are tracked so they can be drained at shutdown via
:meth:aclose.
has_listeners(event_name)
¶
Return True if any interceptor or observer is registered for event_name.
Hot path: callers use this to skip detail-dict / Event construction
when no one will receive the event. defaultdict.get returns None
for missing keys without inserting an empty list.
intercept(event_name, handler)
¶
Register an interception handler for event_name.
on(event_name, handler)
¶
Register an observation handler for event_name.