nodus-events
Distributed event bus with Redis pub/sub, source-instance deduplication, and pre-rehydration buffering.
Local-first: events are recorded in the in-process AuditStore and optionally
broadcast over Redis pub/sub when [redis] is installed. No required
external dependencies — the bus works fully in local mode without Redis.
Status: v0.1.0 — prepared, not yet published.
Install
pip install nodus-events
# With Redis pub/sub support:
pip install "nodus-events[redis]"
What it provides
| Component | Purpose |
|---|---|
EventBus |
Publish events locally and optionally via Redis pub/sub |
EventBusConfig |
Connection settings, channel, instance ID, buffer config |
Event |
Typed event record with type, payload, correlation ID, timestamp |
AuditStore / InMemoryAuditStore |
Persistent event log (protocol + in-memory impl) |
get_event_bus() |
Process-level singleton factory |
publish_event() |
Convenience wrapper for one-line event emission |
Quick start
from nodus_events import publish_event, get_event_bus
# One-liner emission (uses process singleton)
publish_event("user.created", payload={"user_id": "u123"}, correlation_id="req-abc")
# Direct bus access
bus = get_event_bus()
bus.publish("flow.completed", payload={"flow_id": "f1"})
# Read audit log
events = bus.audit_store.list()
Redis pub/sub
from nodus_events import EventBusConfig, get_event_bus
config = EventBusConfig(
redis_url="redis://localhost:6379",
channel="nodus:events",
instance_id="worker-1", # dedup: ignores events from own instance
)
bus = get_event_bus(config)
bus.start_subscriber(callback=lambda event: print(event.event_type))
Events published by this instance are not re-delivered to its own
subscriber — source_instance_id deduplication prevents echo loops.
Stop the subscriber and flush buffered events:
bus.stop()
buffered = bus.drain_buffered_events() # events received before start_subscriber()
Pre-rehydration buffering
Events that arrive over Redis before start_subscriber() is called are
buffered in memory. drain_buffered_events() returns them in order after
the subscriber starts — no events are lost during startup.
EventBusConfig
from nodus_events import EventBusConfig
config = EventBusConfig(
redis_url=None, # None → local-only mode (no Redis)
channel="nodus:events", # Redis pub/sub channel name
enabled=True,
instance_id="worker-1", # unique per process/pod
reconnect_delay_secs=5,
max_buffer_size=1000,
)
Event record
from nodus_events import Event
# Event fields:
event.event_type # str
event.correlation_id # str | None
event.source_instance_id # str
event.payload # dict | None
event.timestamp # float (UTC epoch seconds)
AuditStore protocol
from nodus_events import AuditStore, InMemoryAuditStore
store = InMemoryAuditStore()
store.record(event)
events = store.list() # all events
events = store.list(event_type="user.created")
events = store.list(limit=50)
Implement AuditStore to back the log with a database.
Singleton management
from nodus_events import get_event_bus, reset_event_bus
bus = get_event_bus(config) # creates singleton on first call
bus2 = get_event_bus() # returns same instance (config ignored)
# In tests — reset between cases:
reset_event_bus()
Design
- No required dependencies. Local mode works with zero extras.
Redis is opt-in via
[redis]extra. - Source-instance dedup. Each bus has a unique
instance_id; events it published are not re-delivered to itself. - Pre-rehydration buffer. Events arriving before
start_subscriber()are buffered so no events are dropped during startup. - Thread-safe. Singleton creation and audit store use
threading.Lock.
Development
pip install -e ".[dev]"
pytest tests/ -q
License
MIT — see LICENSE.
Metadata
Release files for nodus-events 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nodus_events-0.1.0.tar.gz | 11.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nodus_events-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.3 kB
Release files / nodus_events-0.1.0.tar.gz
| Download URL | nodus_events-0.1.0.tar.gz |
|---|---|
| Size | 11.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
50695d1c90bbe868729590b2b266c4192301e65b054deada31f478c86a369335
|
|
BLAKE2b-256 checksum How to use checksums |
c4752f1e0d49461ce71bc50709ef04aeb9d900d0549379e1c550bbef4425d2a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / nodus_events-0.1.0-py3-none-any.whl
| Download URL | nodus_events-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a79643c947cd5c75d1730470d970cd17665f68d8e3705611f8dbd1a6e411f524
|
|
BLAKE2b-256 checksum How to use checksums |
d771e6d6dec3e5c65c9b15ec84ef68d05078f572962d89a6dfeed8486ade61b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|