⚡ JAEB — Just Another Event Bus
A lightweight, in-process event bus for Tokio — snapshot-driven dispatch with retry, dead-letter, and middleware support.
✨ Highlights
- 🔀 Sync + Async handlers behind one
subscribeAPI - 🔁 Retry & Dead Letters with per-listener policies
- 🧩 Typed & Global Middleware pipeline
- 📊 Optional Metrics (Prometheus-compatible via
metricscrate) - 🔍 Built-in Tracing support (
tracefeature) - 🛑 Graceful Shutdown with async drain + timeout
- 🏗️ summer-rs Integration for plugin-based auto-registration
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. If you need durable messaging, consider pairing JAEB with an external queue for outbox-style patterns.
Installation
[]
= "0.3.7"
= { = "1", = ["macros", "rt-multi-thread"] }
With metrics instrumentation:
[]
= { = "0.3", = ["metrics"] }
With standalone handler macros:
[]
= { = "0.3", = ["macros"] }
⚡ Quick Start
Full example with sync/async handlers, retry policies, and dead-letter handling:
use Duration;
use ;
;
;
;
async
Architecture
JAEB uses an immutable snapshot registry (ArcSwap) for hot-path reads:
graph LR
P[publish] --> S[Load Snapshot]
S --> GM[Global Middleware]
GM --> TM[Typed Middleware]
TM --> AL[Async Lane - spawned]
TM --> SL[Sync Lane - serialized FIFO]
- 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
FailurePolicy->SubscriptionPolicyNoRetryPolicy->SyncSubscriptionPolicyIntoFailurePolicy->IntoSubscriptionPolicy
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/fire-once- one-shot / fire-once handlerexamples/panic-safety- panic handling behavior in handlersexamples/subscription-lifecycle- subscribe/unsubscribe lifecycleexamples/jaeb-visualizer- TUI visualizer for event bus activityexamples/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 |
trace |
off | Enables tracing spans and events for dispatch diagnostics |
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
use ;
use ;
use Component;
use ;
use ;
/// A dummy database pool registered as a summer Component via a plugin.
;
;
/// Async listener — `DbPool` is injected automatically from summer's DI container.
async
/// Sync dead-letter listener — auto-detected from the `DeadLetter` event type.
async
All #[event_listener] functions are auto-discovered via inventory and subscribed
during plugin startup — no manual registration needed.
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
use Duration;
use ;
async
async
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.