Bridge Architecture
Relevant source files
The following files were used as context for generating this wiki page:
The Bridge Architecture in the bubus project provides a standardized mechanism for forwarding events across different runtimes, processes, and network boundaries. By implementing various bridge types, the system allows an EventBus in one environment (e.g., a Node.js backend) to communicate with an EventBus in another (e.g., a Python service or a browser), using diverse transport layers such as HTTP, WebSockets, Unix Sockets, or message brokers like NATS and Redis.
Bridges typically consist of an inbound_bus for handling received events and methods for dispatching outbound events. They abstract the complexities of serialization, connection management, and protocol-specific logic, providing a uniform emit/on interface similar to the core EventBus.
Sources: bubus-ts/src/bridges.ts:1-20, bubus-ts/src/bridge_postgres.ts:50-70, bubus/bridge_postgres.py:70-85
Core Bridge Mechanism
Every bridge follows a dual-role pattern: acts as a listener (receiving events from an external source and injecting them into a local bus) and a dispatcher (taking local events and sending them to an external target).
Internal Components
- Inbound Bus: A private
EventBusinstance (often initialized withmax_history_size: 0) used to manage local handlers for events arriving through the bridge. - Dispatch/Emit: Methods that serialize
BaseEventobjects and transmit them via the bridge's specific protocol. - Serialization: Most bridges utilize
event.toJSON()orevent.model_dump(mode='json')to ensure events are safe for transport.
Transport Implementations
The project provides several specialized bridge implementations to suit different infrastructure requirements.
Database-Backed Bridges (Postgres & SQLite)
Database bridges use flat tables to persist events and notification mechanisms (like Postgres LISTEN/NOTIFY or SQLite polling) to signal arrival.
| Bridge Type | Persistence | Notification Mechanism | Key Configuration |
|---|---|---|---|
| Postgres | Flat Table | LISTEN / NOTIFY | table_url, channel |
| SQLite | Flat Table | Polling with Cursor | path, table, poll_interval |
Postgres Schema Logic
The Postgres bridge maps event_* fields to individual columns for easier querying while storing the full object in an event_payload column. It uses an UPSERT logic on event_id to prevent duplicates.
Sources: bubus-ts/src/bridge_postgres.ts:10-30, bubus-ts/src/bridge_postgres.ts:85-110, bubus/bridge_postgres.py:100-130
Message Broker Bridges (NATS & Redis)
These bridges utilize pub/sub patterns for low-latency, cross-process event distribution.
File and Socket Bridges
- JSONL Bridge: Appends events to a
.jsonlfile. It tracks abyte_offsetto poll for new lines without re-reading the entire file. - Socket Bridge: Uses Unix Domain Sockets for high-performance IPC on the same host. It enforces a 90-character path limit for socket paths.
Sources: bubus-ts/src/bridge_jsonl.ts:85-110, bubus-ts/src/bridges.ts:40-55
Common Configuration and Lifecycle
Bridges implement a start() and close() lifecycle to manage active connections or polling tasks.
Connection Management
Bridges often utilize a start_promise or _start_lock to prevent race conditions during initialization, ensuring only one connection or listener task is active at a time.
URI/Endpoint Parsing
Bridges use standard URL formats for configuration:
- Redis:
redis://user:pass@host:port/db/channel - Postgres:
postgresql://user:pass@host:port/dbname/tablename - HTTP:
http://host:port/path - Unix:
unix:///path/to/socket
Sources: bubus-ts/src/bridge_redis.ts:35-50, bubus-ts/src/bridge_postgres.ts:32-50, bubus-ts/src/bridges.ts:25-60
Conclusion
The Bridge Architecture provides the "glue" that allows the bubus event system to scale beyond a single memory space. By abstracting transport-specific details into interchangeable bridge classes, the system maintains a consistent programming model regardless of whether events are traveling across a local network via NATS, through a persistent database like Postgres, or between local processes via Unix Sockets.