Skip to main content

Documentation Index

Fetch the complete documentation index at: https://abxbus.archivebox.io/llms.txt

Use this file to discover all available pages before exploring further.

BaseEvent is the typed payload + runtime state object that flows through the bus. Use subclassing (Python) or BaseEvent.extend(...) (TypeScript) to define event payload fields.

Defining events

from abxbus import BaseEvent

class FooCreateEvent(BaseEvent[str]):
    id: str | None = None
    name: str
    age: int
Queue semantics are split in each runtime:
  • Immediate path: await event.now() (Python/TypeScript), event.Now() (Go), event.now().await (Rust)
  • Queue-order path: await event.wait() (Python/TypeScript), event.Wait() (Go), event.wait().await (Rust)
now() and wait() accept the wait-shaping options (first_result and timeout). Result filtering and error policy live on event_result() / event_results_list(). Python also supports await event as a Python-only shortcut for await event.now(). Other runtimes require the explicit now() / wait() methods. In Go the same split is exposed as event.Now() for immediate queue-jump execution and event.Wait() for normal queue-order waiting. In Rust the same split is exposed as event.now().await for immediate queue-jump execution and event.wait().await for normal queue-order waiting. Unset event option fields are not hydrated onto the event at emit time; the bus that actually processes the event resolves its defaults at execution time.

Core metadata fields

Common event metadata fields available in all runtimes:
  • event_id: unique UUIDv7
  • event_type: event name/type key
  • event_version: payload version marker
  • event_result_type: expected handler return schema/type
  • event_timeout: per-event timeout override (None/null means use the current processing bus default at execution time; 0 disables)
  • event_handler_timeout: per-handler timeout cap override
  • event_handler_slow_timeout: per-handler slow warning threshold (None/null means use the current processing bus default; 0 disables)
  • event_slow_timeout: per-event slow warning threshold (None/null means use the current processing bus default; 0 disables)
  • event_concurrency: event scheduling mode override (None/null/zero-value mode means use the current processing bus default)
  • event_handler_concurrency: handler scheduling mode override (None/null/zero-value mode means use the current processing bus default)
  • event_handler_completion: handler completion strategy override (None/null/zero-value mode means use the current processing bus default)

Runtime fields

  • event_status: pending/started/completed
  • event_created_at, event_started_at, event_completed_at
  • event_started_at / event_completed_at are None (Python) / null (TypeScript) until set
  • event_parent_id and event_emitted_by_handler_id are None / null when unset
  • event_blocks_parent_completion: True / true only for linked children awaited from the handler that emitted them
  • event_path: buses traversed
  • event_results: per-handler result entries
  • Child-event tracking (event_children/descendants)

Completion model

Events are returned in pending state from emit(), then complete asynchronously.
pending = bus.emit(MyEvent())
completed = await pending.now()
completed_without_raise = await pending.now()
completed_in_queue_order = await pending.wait()
value = await completed.event_result()

Result access helpers

Result helpers share the same defaults in all runtimes:
  • raise_if_any=true: raise when any handler result is an error.
  • raise_if_none=false: return None / undefined / nil / [] when no result matches the filter.
  • If every handler errors, only raise_if_any=false plus raise_if_none=false suppresses the error. Any other combination raises.
  • A single handler error is raised as that error; multiple handler errors are raised as an aggregate/exception-group shape.

First Result

completed = await event.now(first_result=True)
value = await completed.event_result()

All results

items = await event.event_results_list()
by_handler = {handler_id: result.result for handler_id, result in event.event_results.items()}

Per-handler result entries

You can create/update a specific EventResult entry for a handler (useful for controlled seeding/rehydration flows).
pending = event.event_result_update(handler=handler_entry, eventbus=bus, status='pending')
pending.update(status='completed', result='seeded')

Resetting an event

You can create a fresh pending copy for re-emit.
fresh = event.event_reset()

Serialization

Events are JSON-serializable in all runtimes for bridge and cross-runtime workflows.
payload = event.model_dump(mode='json')
print(payload)
# {
#   "event_id": "0190...",
#   "event_type": "CreateUserEvent",
#   "event_status": "pending",
#   "event_result_type": {"type": "object", "...": "..."},
#   "email": "[email protected]",
#   "...": "..."
# }

restored = type(event).model_validate(payload)

Notes

  • Reserved names are validated in all runtimes:
    • runtime API names such as bus, emit, now, and wait cannot be provided as payload fields where they would collide with event methods/properties.
    • Unknown event_* fields are rejected.
    • Known built-in event_* fields (for example event_timeout) can still be intentionally overridden in event definitions.
  • model_* is also reserved:
    • Python: unknown model_* fields are rejected, but valid Pydantic namespace overrides (for example model_config) are allowed.
    • TypeScript: any model_* field is rejected.
  • event_result_type drives handler return validation in all runtimes.
  • Parent-child tracking is automatic for event.emit(...) inside handlers. bus.emit(...) creates a top-level event with no parent link.

Reserved Fields

from pydantic import ConfigDict
from abxbus import BaseEvent

class AllowedEvent(BaseEvent[None]):
    event_timeout: float | None = 30  # allowed built-in event_* override
    model_config = ConfigDict(extra='allow')  # allowed Pydantic model_* override

# rejected: unknown reserved prefixes
class InvalidEvent(BaseEvent[None]):
    event_some_field_we_dont_recognize: int = 1  # raises
    model_something_random: int = 2  # raises