下面显示的是英文原文。
Patterns
A MemoryPattern subscription reads every name its pattern matches, and the broker's Routing decides who receives a shared match.
Patterns use the NATS subject syntax.
A name splits into tokens at ..
* matches exactly one token, and > as the last token matches one or more.
So orders.* reads orders.eu and orders.us, and orders.> also reads orders.eu.created.
The broker checks a pattern when the subscription opens; a bad one stops the service at startup with MemoryError::InvalidPattern, which names it.
A subscription by name reads one name, and a wildcard token in it stops the service with MemoryError::WildcardName.
MemoryBroker::routing sets the rule for a publish that several subscriptions match.
Routing::EveryMatch, the default, delivers it to every match, as NATS does: a pattern reads beside the handlers of single names, as an audit trail or a metrics tap.
Routing::MostSpecific delivers it to the subscriptions of the exact name, or, where there are none, to the most specific matching pattern: a pattern is the fallback for names without a handler of their own.
Patterns are compared token by token from the left, and at the first difference a literal beats *, and * beats >.
For orders.eu.created, orders.eu.* beats orders.*.created, which beats orders.>, which beats *.eu.created.
A broker with no pattern subscription routes by the exact name alone and pays nothing for patterns.
A pattern subscription does not replay, even on a retaining broker.
Example
orders.eu goes to its own handler alone, and the pattern takes every other region.
- Macros
- Manual
#[subscriber("orders.eu")]
async fn europe(order: &Order) -> HandlerOutcome {
tracing::info!(order.id, "european order");
HandlerOutcome::ack()
}
/// Reads every `orders.<region>` name.
#[subscriber(MemoryPattern::new("orders.*"))]
async fn other_regions(order: &Order) -> HandlerOutcome {
tracing::info!(order.id, "order from another region");
HandlerOutcome::ack()
}
#[ruststream::app]
fn app() -> impl App {
// `orders.eu` goes to `europe` alone; the pattern takes the names nobody else reads.
let broker = MemoryBroker::new().routing(Routing::MostSpecific);
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(broker, |b| {
b.include(europe);
b.include(other_regions);
})
}
struct Europe;
impl Handle<Order> for Europe {
fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
tracing::info!(order.id, "european order");
ready(Ok(()))
}
}
struct OtherRegions;
impl Handle<Order> for OtherRegions {
fn handle(
&self,
order: &Order,
_outs: &(),
_ctx: &mut Context<'_>,
) -> impl Future<Output = Result<(), HandlerOutcome>> {
tracing::info!(order.id, "order from another region");
ready(Ok(()))
}
}
fn app() -> impl App {
// `orders.eu` goes to `Europe` alone; the pattern takes the names nobody else reads.
let broker = MemoryBroker::new().routing(Routing::MostSpecific);
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(broker, |b| {
b.include(subscriber("orders.eu", Europe).build());
// Reads every `orders.<region>` name.
b.include(subscriber(MemoryPattern::new("orders.*"), OtherRegions).build());
})
}