pub struct NamedSubscriber<DB, D = BuiltIn<DB>>where
DB: QueueDatabase + RoleColumns,
D: ByName<DB> + 'static,{ /* private fields */ }Expand description
The subscriber a by-name subscription opens: the claim loop of the table its name’s route leads to.
It claims as an InboxSubscriber does, with the broker’s poll
interval, on a broker whose dialect implements ByName for its database, as
every built-in dialect does. A route whose row leaves every event to
the crate, with role columns of types the crate reads itself, is read by those columns alone,
in the row lock form and in the lease form: no box and no dynamic call per message. Each
column is held to the type the struct reads it as, so a row that would not decode into the
struct goes to the decode-failure policy here too. The types are an i16, i32, i64,
String or Vec<u8> id, a Vec<u8> or String payload, headers as JSON, a text or byte key,
an integer attempt, chrono or time times and leases, and
SystemClock or DatabaseClock. Any other row
runs its own code: each delivery is boxed, each settlement is a dynamic call whose future is
boxed, and each poll of the stream is a dynamic call.
A mount that declares max_attempts(..) or dead_letter(..) on a name is refused at startup:
an InboxQueue descriptor takes those.
§Examples
use ruststream::OutgoingMessage;
use ruststream_sqlx::prelude::*;
use serde::Deserialize;
use sqlx::{PgConnection, PgPool, Postgres};
#[derive(Inbox, sqlx::FromRow)]
#[inbox(table = "report_jobs")]
pub struct Report {
#[field(id, generated)]
id: i64,
#[field(group)]
name: String,
#[field(payload)]
payload: Vec<u8>,
}
impl Publish<Postgres> for Report {
async fn publish(
conn: &mut PgConnection,
message: &OutgoingMessage<'_>,
) -> Result<(), sqlx::Error> {
sqlx::query("INSERT INTO report_jobs (name, payload) VALUES ($1, $2)")
.bind(message.name())
.bind(message.payload())
.execute(conn)
.await?;
Ok(())
}
}
#[derive(Deserialize)]
struct Request {
day: String,
}
// Each by-name mount opens a `NamedSubscriber`; the route's prefix leads both names into
// `report_jobs`, and each reads its own group.
#[subscriber("reports.daily")]
async fn daily(request: &Request) -> HandlerOutcome {
tracing::info!(day = %request.day, "daily report");
HandlerOutcome::ack()
}
#[subscriber("reports.weekly")]
async fn weekly(request: &Request) -> HandlerOutcome {
tracing::info!(day = %request.day, "weekly report");
HandlerOutcome::ack()
}
pub fn app(pool: PgPool) -> RustStream {
RustStream::new(AppInfo::new("reports", "0.1.0")).with_broker(
SqlxBroker::new(pool).route::<Report>("reports.*"),
|b| {
b.include(daily);
b.include(weekly);
},
)
}Trait Implementations§
Source§impl<DB, D> Debug for NamedSubscriber<DB, D>where
DB: QueueDatabase + RoleColumns,
D: ByName<DB> + 'static,
impl<DB, D> Debug for NamedSubscriber<DB, D>where
DB: QueueDatabase + RoleColumns,
D: ByName<DB> + 'static,
Source§impl<DB, D> Subscriber for NamedSubscriber<DB, D>where
DB: QueueDatabase + RoleColumns,
D: ByName<DB> + 'static,
impl<DB, D> Subscriber for NamedSubscriber<DB, D>where
DB: QueueDatabase + RoleColumns,
D: ByName<DB> + 'static,
Source§type Message = NamedDelivery<DB, D>
type Message = NamedDelivery<DB, D>
Source§type Error = SqlxBrokerError
type Error = SqlxBrokerError
Auto Trait Implementations§
impl<DB, D = BuiltIn<DB>> !RefUnwindSafe for NamedSubscriber<DB, D>
impl<DB, D = BuiltIn<DB>> !UnwindSafe for NamedSubscriber<DB, D>
impl<DB, D> Freeze for NamedSubscriber<DB, D>where
Opened<DB, D>: Freeze,
impl<DB, D> Send for NamedSubscriber<DB, D>where
Opened<DB, D>: Send,
impl<DB, D> Sync for NamedSubscriber<DB, D>where
Opened<DB, D>: Sync,
impl<DB, D> Unpin for NamedSubscriber<DB, D>where
Opened<DB, D>: Unpin,
impl<DB, D> UnsafeUnpin for NamedSubscriber<DB, D>where
Opened<DB, D>: UnsafeUnpin,
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<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
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