Skip to main content
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 both runtimes:
  • Immediate path: await event (Python) / await event.done() (TypeScript)
  • Queue-order path: await event.event_completed() (Python) / await event.eventCompleted() (TypeScript)

Core metadata fields

Common event metadata fields available in both 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)
  • event_handler_timeout: per-handler timeout cap override
  • event_handler_slow_timeout: per-handler slow warning threshold
  • event_concurrency: event scheduling mode override (None/null means use the current processing bus default)
  • event_handler_concurrency: handler scheduling mode override (None/null means use the current processing bus default)
  • event_handler_completion: handler completion strategy override (None/null 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_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
completed_in_queue_order = await pending.event_completed()
value = await completed.event_result()

Result access helpers

first()

value = await event.first()
# equivalent: await event.event_result(...) with first-completion mode

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 both implementations 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 both runtimes:
    • bus and first are reserved runtime APIs and cannot be provided as payload fields.
    • 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 both runtimes.
  • Parent-child tracking is automatic when events are emitted from handlers.

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