Expand description
Domain event bus — typed pub-sub for application events, separate from
the ORM. Use it for cross-component fan-out (OrderPlaced → mail +
billing + audit). For per-model lifecycle hooks use signals instead.
See events::EventBus.
Domain event bus: typed pub-sub for application events, separate
from the ORM.
§This or crate::signals?
signalshook aModellifecycle (pre/post save, pre/post delete). Use them for “whenever row X changes, do Y”.eventsare not tied to a model. Use them for “an order was placed”, where mail, billing and audit each react on their own.
Both are typed, async, multi-subscriber and dispatch in order.
§Quick start
ⓘ
use rustango::events::EventBus;
use std::sync::Arc;
#[derive(Clone)]
struct OrderPlaced { order_id: i64, total_cents: i64 }
let bus = EventBus::new();
// Subscribe (anywhere — main, app init, a service constructor):
bus.subscribe::<OrderPlaced, _>(|e| Box::pin(async move {
println!("billing: charging {} cents for order {}", e.total_cents, e.order_id);
})).await;
// Publish (from a handler, a job, a worker):
bus.publish(OrderPlaced { order_id: 42, total_cents: 9999 }).await;§Semantics
- Subscribers run one at a time, in subscription order. For
parallel fan-out,
tokio::spawninside the subscriber. - The event is cloned once per subscriber, so
Emust beClone + Send + Sync + 'static. - A panicking subscriber is logged and skipped; the rest still run
and
publishreturns normally. - The bus is cheap to clone; state is shared. Pass clones into axum state or your services.
Structs§
- Event
Bus - In-process domain event bus. Cheap to clone; clones share state.
- Subscriber
Id - Opaque identifier returned by
EventBus::subscribefor later use withEventBus::unsubscribe.
Type Aliases§
- Handler
Future - Future returned by event handlers.
'staticbecause the handler is stored asArc<dyn ...>and may run after the caller returns.