pub struct PulsarBroker { /* private fields */ }Expand description
An Apache Pulsar broker for the RustStream messaging framework.
new is synchronous and records only configuration; the runtime dials once at startup via
the consuming Broker::connect. That is what lets a service compose with the synchronous
#[ruststream::app] builder.
§Examples
use std::env;
use ruststream_pulsar::prelude::*;
#[ruststream::app]
fn app() -> impl App {
let mut broker = PulsarBroker::new("pulsar+ssl://pulsar.acme.internal:6651");
if let Ok(token) = env::var("PULSAR_TOKEN") {
broker = broker.token(token);
}
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(broker, |b| {
b.include(handle);
})
}A test runs the app main runs. With the testing feature, TestApp::start connects this
broker in process, with no server, and the test addresses it by its production type:
use std::error::Error;
use ruststream::testing::TestApp;
use ruststream_pulsar::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Eq, Outgoing, PartialEq, Serialize)]
struct Order {
id: u64,
quantity: u32,
}
#[subscriber(PulsarSubscription::new("orders", "workers"))]
async fn handle(order: &Order) -> HandlerOutcome {
if order.quantity == 0 {
return HandlerOutcome::drop();
}
HandlerOutcome::ack()
}
/// The app `main` runs, and the one the tests hand the harness.
pub fn app() -> RustStream {
RustStream::new(AppInfo::new("orders", "0.1.0"))
.with_broker(PulsarBroker::new("pulsar://localhost:6650"), |b| {
b.include(handle);
})
}
pub async fn an_empty_order_is_dropped() -> Result<(), Box<dyn Error>> {
let tb = TestApp::start(app()).await?;
// The publish returns once the handler it woke has settled.
tb.broker::<PulsarBroker>()
.message(&Order { id: 1, quantity: 0 })
.to("orders")
.publish()
.await?;
tb.broker::<PulsarBroker>()
.subscriber("orders")
.assert_called_once()
.with(&Order { id: 1, quantity: 0 })
.settled(HandlerOutcome::drop());
tb.shutdown().await?;
Ok(())
}Implementations§
Source§impl PulsarBroker
impl PulsarBroker
Sourcepub fn new(url: impl Into<String>) -> Self
pub fn new(url: impl Into<String>) -> Self
Records the service URL (pulsar:// or pulsar+ssl://). No I/O.
Sourcepub fn default_subscription(self, subscription: impl Into<String>) -> Self
pub fn default_subscription(self, subscription: impl Into<String>) -> Self
The durable subscription a subscription by bare topic name joins.
#[subscriber("orders")] names a topic and no subscription, and Pulsar has no anonymous
consumer, so the name comes from here. A subscription name is the cursor on the server:
every consumer under it shares one backlog, the handlers of this service and those of any
other service that names the same one. Name it after the service that owns the cursor.
A bare topic name on a broker without it fails at startup with
PulsarError::Invalid naming this setting; a PulsarSubscription names its own
subscription and needs none.
§Examples
use ruststream_pulsar::prelude::*;
/// Joins the `orders-worker` subscription on `orders`, with every other instance of the
/// service.
#[subscriber("orders")]
async fn handle(order: &Order) -> HandlerOutcome {
tracing::info!(order.id, "accepted");
HandlerOutcome::ack()
}
#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(
PulsarBroker::new("pulsar://localhost:6650").default_subscription("orders-worker"),
|b| {
b.include(handle);
},
)
}Sourcepub fn operation_retries(self, retries: OperationRetries) -> Self
pub fn operation_retries(self, retries: OperationRetries) -> Self
Bounds how long the client keeps asking for an operation a server has not accepted.
Left alone, the client retries such an answer for ever, five seconds apart, which is what
waits out a broker that is restarting. The same patience covers a subscription the server
refuses because another consumer holds it, so a second consumer of an
Exclusive subscription neither takes it nor
reports anything - it waits, and the service does not start. A service that has to hear
about that instead bounds the tries here, and subscribe then returns
PulsarError::Subscribe naming the topic.
The bound is the connection’s, not one operation’s: it covers the lookups, the producers and the consumer’s own reconnect after a disconnect, so a short bound turns a long outage into a subscription that gives up rather than one that waits.
§Examples
use ruststream_pulsar::prelude::*;
#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(
PulsarBroker::new("pulsar://localhost:6650")
.operation_retries(OperationRetries::attempts(nonzero!(3u32))),
|b| {
b.include(handle);
},
)
}Sourcepub fn max_message_size(self, bytes: NonZeroUsize) -> Self
pub fn max_message_size(self, bytes: NonZeroUsize) -> Self
The largest payload a publish may carry, in bytes: the server’s maxMessageSize, five
mebibytes unless the deployment raised or lowered it.
A larger publish fails with PulsarError::Publish before it leaves the service. The
client does not check the size itself, and a server answers an oversized frame by
dropping the connection, which fails every producer and consumer sharing it; the
in-process mode refuses the same publishes.
§Examples
use ruststream_pulsar::prelude::*;
#[ruststream::app]
fn app() -> impl App {
// The cluster runs with `maxMessageSize=10485760`.
RustStream::new(AppInfo::new("archive", "0.1.0")).with_broker(
PulsarBroker::new("pulsar://localhost:6650")
.max_message_size(nonzero!(10_485_760usize)),
|b| {
b.include(archive);
},
)
}Sourcepub fn publisher(&self) -> PulsarPublisher
pub fn publisher(&self) -> PulsarPublisher
A publisher sharing this broker’s connection cell; buildable before connect.
Trait Implementations§
Source§impl Broker for PulsarBroker
impl Broker for PulsarBroker
Source§type Error = PulsarError
type Error = PulsarError
Source§type Connected = ConnectedPulsarBroker
type Connected = ConnectedPulsarBroker
connect
succeeded.Source§impl Clone for PulsarBroker
impl Clone for PulsarBroker
Source§impl Debug for PulsarBroker
impl Debug for PulsarBroker
Source§impl DescribeServer for PulsarBroker
The description carries the address a client dials and nothing else: the generated AsyncAPI
document is published and shared, so a user:password@ in the service URL must not reach it.
ServerSpec::from_url is the framework’s own reduction, so every broker crate drops the
userinfo the same way.
impl DescribeServer for PulsarBroker
The description carries the address a client dials and nothing else: the generated AsyncAPI
document is published and shared, so a user:password@ in the service URL must not reach it.
ServerSpec::from_url is the framework’s own reduction, so every broker crate drops the
userinfo the same way.
Source§fn describe_server(&self) -> ServerSpec
fn describe_server(&self) -> ServerSpec
Source§impl InProcess for PulsarBroker
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 client and every setting of this broker.
impl InProcess for PulsarBroker
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 client and every setting of this broker.
The service URL is parsed as the client parses it, so a broker a service could not connect is
not one a test can connect either. The connection cell is the one connect fills, so a
publisher taken from the broker before the harness connected it publishes in process.
Auto Trait Implementations§
impl !RefUnwindSafe for PulsarBroker
impl !UnwindSafe for PulsarBroker
impl Freeze for PulsarBroker
impl Send for PulsarBroker
impl Sync for PulsarBroker
impl Unpin for PulsarBroker
impl UnsafeUnpin for PulsarBroker
Blanket Implementations§
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,
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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