JAEB - Just Another Event Bus
In-process, snapshot-driven event bus for Tokio applications.
JAEB focuses on correctness and observability for monolith-style event-driven Rust services:
- sync + async handlers behind one
subscribeAPI - compile-time policy validation (retry policies cannot be used with sync handlers)
- listener priority with FIFO stability for equal priorities
- typed and global middleware
- dead-letter stream with recursion guard
- graceful shutdown with in-flight async drain
- optional metrics (
metricsfeature) and built-in tracing - optional standalone macros (
macrosfeature):#[handler]andregister_handlers! - summer-rs integration via summer-jaeb and
#[event_listener]macro support summer-jaeb-macros
When to use JAEB
Use JAEB when you need:
- domain events inside one process (e.g.
OrderCreated-> projections, notifications, audit) - decoupled modules with type-safe fan-out
- retry/dead-letter behavior per listener
- deterministic sync-lane ordering with priority hints
JAEB is not a message broker. It does not provide persistence, replay, or cross-process delivery.
Installation
[]
= "0.3.5"
= { = "1", = ["macros", "rt-multi-thread"] }
With metrics instrumentation:
[]
= { = "0.3.5", = ["metrics"] }
With standalone handler macros:
[]
= { = "0.3.5", = ["macros"] }
Quick Start
use Duration;
use ;
;
;
;
async
Architecture
JAEB uses an immutable snapshot registry (ArcSwap) for hot-path reads:
publish(event)
-> load snapshot (lock-free)
-> global middleware
-> typed middleware
-> async lane (spawned)
-> sync lane (serialized FIFO, priority-ordered)
- async and sync listeners are separated per event type
- priority is applied per lane (higher first)
- equal priority preserves registration order
API Highlights
EventBus::builder()for buffer size, timeouts, concurrency limit, and default policydefault_subscription_policy(SubscriptionPolicy)sets fallback policy forsubscribesubscribe_with_policy(handler, policy)accepts:SubscriptionPolicyfor async handlersSyncSubscriptionPolicyfor sync handlers and once handlers
publishwaits for sync listeners and task-spawn for async listenerstry_publishis non-blocking and returnsEventBusError::ChannelFullon saturation
Core policy types:
SubscriptionPolicy { priority, max_retries, retry_strategy, dead_letter }SyncSubscriptionPolicy { priority, dead_letter }IntoSubscriptionPolicy<M>sealed trait for compile-time mode/policy safety
Backward-compatible aliases remain available (deprecated):
FailurePolicy->SubscriptionPolicyNoRetryPolicy->SyncSubscriptionPolicyIntoFailurePolicy->IntoSubscriptionPolicy
Performance
See BENCHMARK.md for:
- cross-library benchmark setup (
jaebvseventbuzzvsevno) - reproducible benchmark command
- measured results and caveats
- documented
evnocontention benchmark hang under this environment
Examples
examples/basic-pubsub- minimal publish/subscribeexamples/sync-handler- sync dispatch lane behaviorexamples/closure-handlers- closure-based handlersexamples/retry-strategies- fixed/exponential/jitter retry configurationexamples/dead-letters- dead-letter subscription and inspectionexamples/middleware- global and typed middlewareexamples/backpressure-try_publishsaturation behaviorexamples/concurrency-limit- max concurrent async handlersexamples/graceful-shutdown- controlled shutdown and drainingexamples/introspection-EventBus::stats()outputexamples/axum-integration- axum REST app publishing domain eventsexamples/macro-handlers- standalone#[handler]+register_handlers!examples/macro-handlers-auto- standalone#[handler]auto-discovery withregister_handlers!(bus)examples/jaeb-demo- full demo with tracing + metrics exporterexamples/summer-jaeb-demo- summer-rs plugin +#[event_listener]
Run an example:
Feature Flags
| Flag | Default | Description |
|---|---|---|
macros |
off | Re-exports #[handler] and register_handlers! |
metrics |
off | Enables Prometheus-compatible instrumentation via metrics |
test-utils |
off | Exposes TestBus helpers for integration tests |
When metrics is enabled, JAEB records:
eventbus.publish(counter, per event type)eventbus.handler.duration(histogram, per event type)eventbus.handler.error(counter, per event type)eventbus.handler.join_error(counter, per event type)
summer-rs Integration
Use summer-jaeb and summer-jaeb-macros for plugin-based auto-registration via #[event_listener].
Macro support includes:
retriesretry_strategyretry_base_msretry_max_msdead_letterpriorityname
Standalone Macros
Enable the macros feature to use #[handler] and register_handlers! without
summer-rs.
The #[handler] macro generates a struct named <FunctionName>Handler and an
async register(&EventBus) method. Policy attributes are supported:
retriesretry_strategyretry_base_msretry_max_msdead_letterpriorityname
Notes
- JAEB requires a running Tokio runtime.
- Events must be
Send + Sync + 'static; async handlers also requireClone. - The crate enforces
#![forbid(unsafe_code)].
License
jaeb is distributed under the MIT License.
Copyright (c) 2025-2026 Linke Thomas
This project uses third-party libraries. See THIRD-PARTY-LICENSES for dependency and license details.