Skip to main content
Immediate execution lets a handler emit a child event and await it like a direct async function call. When this happens inside a handler, the child event is processed immediately (queue-jump) instead of waiting behind unrelated queued events. Repository example files:

Core pattern

from bubus import BaseEvent, EventBus

class ParentEvent(BaseEvent[str]):
    pass

class ChildEvent(BaseEvent[str]):
    pass

bus = EventBus('RpcBus')

async def on_parent(event: ParentEvent) -> str:
    assert event.bus is not None
    child = event.bus.emit(ChildEvent())
    await child  # queue-jump while still inside this handler
    value = await child.event_result()
    return f'parent got: {value}'

async def on_child(_: ChildEvent) -> str:
    return 'child response'

bus.on(ParentEvent, on_parent)
bus.on(ChildEvent, on_child)

Execution order example

In this pattern, sibling work can already be queued, but the awaited child still runs first.
from bubus import BaseEvent, EventBus

class ParentEvent(BaseEvent):
    pass

class ChildEvent(BaseEvent):
    pass

class SiblingEvent(BaseEvent):
    pass

bus = EventBus('OrderBus', event_concurrency='bus-serial', event_handler_concurrency='serial')
order: list[str] = []

async def on_parent(event: ParentEvent) -> None:
    assert event.bus is not None
    order.append('parent_start')
    event.bus.emit(SiblingEvent())
    child = event.bus.emit(ChildEvent())
    await child
    order.append('parent_end')

async def on_child(_: ChildEvent) -> None:
    order.append('child')

async def on_sibling(_: SiblingEvent) -> None:
    order.append('sibling')

bus.on(ParentEvent, on_parent)
bus.on(ChildEvent, on_child)
bus.on(SiblingEvent, on_sibling)

await bus.emit(ParentEvent())
await bus.wait_until_idle()

assert order.index('child') < order.index('parent_end')
assert order.index('parent_end') < order.index('sibling')

Interaction with concurrency modes

  • event_concurrency = global-serial: queue-jump still works, but all buses still share one global event slot.
  • event_concurrency = bus-serial: queue-jump preempts that bus queue; other buses can continue processing independently.
  • event_concurrency = parallel: events may already overlap; queue-jump still reduces parent latency for awaited child calls.
  • event_handler_concurrency = serial: parent temporarily yields execution so child handlers can run without deadlock.
  • event_handler_concurrency = parallel: child handlers can overlap with other handlers for the same event.
  • event_handler_completion = first: winner semantics can cancel loser handlers and their in-flight child work.

Notes

  • In Python, await child_event inside a handler is the immediate path.
  • In TypeScript, use await child_event.done() or await child_event.immediate().
  • In TypeScript, await child_event.waitForCompletion() keeps normal queue order (non-queue-jump wait).