pub struct LapinBroker { /* private fields */ }Expand description
A RabbitMQ broker backed by lapin: configuration captured, no I/O
performed yet.
new is synchronous and records only the connection settings, so a RabbitMQ
service is assembled with the synchronous #[ruststream::app] builder like any other broker.
The runtime calls Broker::connect once at startup, which consumes this value and yields
the ConnectedLapinBroker witness: subscriptions, publishers, and requesters exist only
from there, so “not connected” is not representable.
By default the broker never creates infrastructure: descriptors describe the EXPECTED
topology, and a missing queue is a subscribe error. Opt into declaration with
declare_topology(true).
§Examples
use ruststream_lapin::prelude::*;
use serde::Deserialize;
#[derive(Deserialize)]
struct Order {
id: u64,
}
#[subscriber("orders")]
async fn handle(order: &Order) -> HandlerOutcome {
tracing::info!(order.id, "accepted");
HandlerOutcome::ack()
}
fn app() -> RustStream {
let broker = LapinBroker::new("amqp://localhost:5672")
.prefetch(nonzero!(64))
.declare_topology(true);
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(broker, |b| {
b.include(handle);
})
}§Testing
With the testing feature, TestApp::start runs the service’s own app with the broker in
process, and a test addresses it by its production type:
use std::error::Error;
use ruststream::testing::TestApp;
use ruststream_lapin::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq, Outgoing)]
#[outgoing(name = "payments")]
struct Payment {
amount: u64,
}
#[subscriber(RabbitQueue::new("payments"))]
async fn accept(payment: &Payment) -> HandlerOutcome {
if payment.amount == 0 {
return HandlerOutcome::drop();
}
HandlerOutcome::ack()
}
/// The app `main` runs.
pub fn app() -> RustStream {
RustStream::new(AppInfo::new("payments", "0.1.0"))
.with_broker(LapinBroker::new("amqp://rabbit:5672"), |b| {
b.include(accept);
})
}
pub async fn accepts_a_payment() -> Result<(), Box<dyn Error>> {
let tb = TestApp::start(app()).await?;
// The publish returns once the handler it woke has settled.
tb.broker::<LapinBroker>()
.message(&Payment { amount: 100 })
.publish()
.await?;
tb.broker::<LapinBroker>()
.subscriber("payments")
.assert_called_once()
.with(&Payment { amount: 100 })
.settled(HandlerOutcome::ack());
tb.shutdown().await?;
Ok(())
}Implementations§
Source§impl LapinBroker
impl LapinBroker
Sourcepub fn new(uri: impl Into<String>) -> Self
pub fn new(uri: impl Into<String>) -> Self
Records the connection URI; no I/O happens until Broker::connect.
The URI carries credentials, virtual host, and TLS scheme:
amqp://user:pass@host:5672/vhost (or amqps:// with a TLS feature enabled).
Sourcepub fn connection_name(self, name: impl Into<String>) -> Self
pub fn connection_name(self, name: impl Into<String>) -> Self
A connection name shown in the RabbitMQ management UI.
Sourcepub fn prefetch(self, prefetch: NonZeroU16) -> Self
pub fn prefetch(self, prefetch: NonZeroU16) -> Self
Caps unacknowledged deliveries in flight per subscription (basic.qos).
This is the back-pressure window for subscriber streams; individual queue descriptors can override it. Without it the server imposes no prefetch limit.
The count is a NonZeroU16 because AMQP reads basic.qos(0) as “no limit”, the exact
opposite of a cap: the zero sentinel is unrepresentable here, and leaving the prefetch
unset is how “unlimited” is spelled.
Sourcepub fn declare_topology(self, declare: bool) -> Self
pub fn declare_topology(self, declare: bool) -> Self
Whether subscribing declares the descriptor’s expected topology first. Defaults to
false: managing infrastructure is the user’s job, so creation is a deliberate opt-in.
When enabled, subscribing declares the bound exchanges (except the built-in amq.*
ones and the default exchange), the queue, and the bindings.
Trait Implementations§
Source§impl Broker for LapinBroker
impl Broker for LapinBroker
Source§async fn connect(self) -> Result<Self::Connected, Self::Error>
async fn connect(self) -> Result<Self::Connected, Self::Error>
Opens the connection and its shared publish channel, consuming the configuration.
§Errors
Returns AmqpError::Connect when the URI cannot be parsed or the connection fails.
Source§type Connected = ConnectedLapinBroker
type Connected = ConnectedLapinBroker
connect
succeeded.Source§impl Clone for LapinBroker
impl Clone for LapinBroker
Source§impl Debug for LapinBroker
impl Debug for LapinBroker
Source§impl DescribeServer for LapinBroker
DescribeServer reports the configured AMQP address, which is what the AsyncAPI document
records for the service.
impl DescribeServer for LapinBroker
DescribeServer reports the configured AMQP address, which is what the AsyncAPI document
records for the service.
The document is published and shared, so the credentials an AMQP URI carries must not reach it.
ServerSpec::from_url drops them, along with the scheme and the vhost path.
Source§fn describe_server(&self) -> ServerSpec
fn describe_server(&self) -> ServerSpec
Source§impl InProcess for LapinBroker
Available on crate feature testing only.The in-process mode: the connected form a test runs the production app against, carrying the
in-process transport in place of the connection and every setting of this broker.
impl InProcess for LapinBroker
testing only.The in-process mode: the connected form a test runs the production app against, carrying the in-process transport in place of the connection and every setting of this broker.
The URI is parsed as connect parses it, so a broker a service could not connect is not one a
test can connect either.
Auto Trait Implementations§
impl Freeze for LapinBroker
impl RefUnwindSafe for LapinBroker
impl Send for LapinBroker
impl Sync for LapinBroker
impl Unpin for LapinBroker
impl UnsafeUnpin for LapinBroker
impl UnwindSafe for LapinBroker
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<B> BrokerRegistration for Bwhere
B: Broker + 'static,
impl<B> BrokerRegistration for Bwhere
B: Broker + 'static,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more