event_timeout, event_concurrency, event_handler_concurrency, and event_handler_completion stay unset on the event unless the user set them, and each processing bus applies its own defaults at execution time.
Repository example files:
examples/forwarding_between_busses.pyabxbus-ts/examples/forwarding_between_busses.tsabxbus-rust/tests/test_eventbus_forwarding.rs
Why multiple buses are useful
Multiple buses let you separate concerns and tune runtime behavior per boundary:- service-local bus for business logic with strict ordering and useful history
- transport/relay bus focused on throughput and forwarding (little or no history retention)
- specialized buses for domains that need different timeout or concurrency policies
Example: service buses with different policies
In this example:AuthBusis strict and debuggable:event_concurrency='bus-serial',event_handler_concurrency='serial',max_history_size=100RelayBusis a transport forwarder:event_concurrency='parallel',max_history_size=0BillingBusis another service bus with its own settings
- Python
- TypeScript
- Rust
- Go
Uni-directional and bi-directional forwarding
Forwarding can be one-way or two-way depending on your topology.- Uni-directional: one producer bus forwards to one consumer bus.
- Bi-directional: both buses forward to each other (common for peer sync).
- Python
- TypeScript
- Rust
- Go
event_path), forwarding back to that bus is a no-op and it is not re-processed there.
How loop prevention works (event_path)
Loop prevention is automatic and based on event_path:
- Each bus appends its own label (for example
AuthBus#a8d1) toevent_pathwhen it first sees an event. - When a forwarding handler points to another bus, that bus checks whether its label is already in
event_path. - If yes, forwarding to that bus is skipped (no-op), so cycles terminate naturally.
- Python
- TypeScript
- Rust
- Go
Parent-child tracking across forwarded flows
Parent-child tracking also works across forwarded flows:- if a forwarded event is handled on a downstream bus and that handler emits a child with
event.emit(...), the child still links back to the parent viaevent_parent_id - nested descendants emitted on downstream buses keep that lineage as they continue through forwarding
- this remains true for both queue-jumped children (
await child.now()) and normally queued children (emitted but not immediately awaited) bus.emit(...)inside a handler remains detached top-level work with no parent link