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.
global-serial enforces a single global event-processing slot across all EventBus instances.
Note that the global lock is scoped to the EventBus class; if you need separate global lock domains, subclass EventBus.
Companion runnable example:
Lifecycle impact
- An emitted event is queued on its target bus as usual.
- Before handler execution starts, the bus acquires the shared global event lock.
- While one event is running anywhere, other buses wait.
- Handler-level concurrency still applies inside that one active event.
Execution order example
import asyncio
from abxbus import BaseEvent, EventBus
class SerialEvent(BaseEvent):
order: int
source: str
bus_a = EventBus('GlobalSerialA', event_concurrency='global-serial')
bus_b = EventBus('GlobalSerialB', event_concurrency='global-serial')
in_flight = 0
max_in_flight = 0
starts: list[str] = []
async def handler(event: SerialEvent) -> None:
global in_flight, max_in_flight
in_flight += 1
max_in_flight = max(max_in_flight, in_flight)
starts.append(f'{event.source}:{event.order}')
await asyncio.sleep(0.01)
in_flight -= 1
bus_a.on(SerialEvent, handler)
bus_b.on(SerialEvent, handler)
for i in range(3):
bus_a.emit(SerialEvent(order=i, source='a'))
bus_b.emit(SerialEvent(order=i, source='b'))
await bus_a.wait_until_idle()
await bus_b.wait_until_idle()
assert max_in_flight == 1
assert [s for s in starts if s.startswith('a:')] == ['a:0', 'a:1', 'a:2']
assert [s for s in starts if s.startswith('b:')] == ['b:0', 'b:1', 'b:2']
import { BaseEvent, EventBus } from 'abxbus'
import { z } from 'zod'
const SerialEvent = BaseEvent.extend('SerialEvent', {
order: z.number(),
source: z.string(),
})
const busA = new EventBus('GlobalSerialA', { event_concurrency: 'global-serial' })
const busB = new EventBus('GlobalSerialB', { event_concurrency: 'global-serial' })
let inFlight = 0
let maxInFlight = 0
const starts: string[] = []
const handler = async (event: InstanceType<typeof SerialEvent>) => {
inFlight += 1
maxInFlight = Math.max(maxInFlight, inFlight)
starts.push(`${event.source}:${event.order}`)
await new Promise((resolve) => setTimeout(resolve, 10))
inFlight -= 1
}
busA.on(SerialEvent, handler)
busB.on(SerialEvent, handler)
for (let i = 0; i < 3; i += 1) {
busA.emit(SerialEvent({ order: i, source: 'a' }))
busB.emit(SerialEvent({ order: i, source: 'b' }))
}
await busA.waitUntilIdle()
await busB.waitUntilIdle()
if (maxInFlight !== 1) throw new Error('expected global serialization')
Notes
- This mode is strongest for determinism across distributed in-process bus topologies.
- Queue-jump behavior (
await event inside handlers) still applies, but it does so under the same global lock.