Skip to main content
all is the default handler completion mode. The event completes only after every matching handler reaches a terminal state.

Lifecycle impact

  1. All matching handlers are allowed to run.
  2. A successful early handler does not short-circuit the event.
  3. Event completion waits for every handler to finish, fail, or time out.
  4. Result collection includes all successful non-None / non-undefined return values.

Execution order example

import asyncio
from bubus import BaseEvent, EventBus

class CompletionEvent(BaseEvent[str]):
    pass

bus = EventBus(
    'CompletionAllBus',
    event_handler_concurrency='parallel',
    event_handler_completion='all',
)

seen: list[str] = []

async def fast_handler(_: CompletionEvent) -> str:
    await asyncio.sleep(0.01)
    seen.append('fast')
    return 'fast'

async def slow_handler(_: CompletionEvent) -> str:
    await asyncio.sleep(0.05)
    seen.append('slow')
    return 'slow'

bus.on(CompletionEvent, fast_handler)
bus.on(CompletionEvent, slow_handler)

event = bus.emit(CompletionEvent())
await event

assert set(seen) == {'fast', 'slow'}
results = await event.event_results_by_handler_name(raise_if_any=False, raise_if_none=False)
assert set(results.values()) == {'fast', 'slow'}

Notes

  • all is best when multiple handlers contribute required side effects.
  • Handler scheduling (serial vs parallel) changes overlap, but not the fact that all handlers must settle.