pub struct InboxDelivery<DB: QueueDatabase, Row: Events<DB>, Mode = Plain> { /* private fields */ }Expand description
One claimed row in a handler’s hands.
In payload mode the payload is lent from the row, without a copy. In row mode the delivery
lends its handler the row itself, as the driver read it, with no codec in between. A headers
column becomes the delivery’s headers, and the row it lends holds that column empty. A claimed
id without a row, and a row the driver could not read, lend no row: the runtime settles them by
the decode policy.
In the row lock form the delivery holds the claim’s transaction: settling it runs one statement and commits, and dropping it unsettled rolls the transaction back, which returns the row to the queue at once. In the lease form the delivery holds the lease its claim wrote, which its subscription extends each half lease: settling it runs one statement on a connection of its own, which takes effect only while the row still holds that lease. A lease delivery dropped unsettled releases its row at once, on the runtime the broker connected on; with that runtime gone, the row returns once the lease runs out.
In the advisory lock form the delivery holds a connection whose session holds the lock on the
row’s key: settling it runs one statement on that connection, then releases the lock and
returns the connection to the pool. A delivery dropped unsettled closes its connection on the
runtime the broker connected on, after releasing the lock, and its row returns at once; with
that runtime gone the connection closes as it drops, and the server ends its session and its
lock. A settlement after shutdown released its lock
fails with SqlxBrokerError::Closed.
In transactional mode the delivery lends its handler the transaction it settles in, and the
handler’s writes go with the settlement: acknowledgement runs its statement and commits them
together; every other settlement first discards what the handler wrote, then settles as outside
transactional mode. A statement that fails rolls the whole transaction back, and the row
returns at once. In the lease form the acknowledgement runs in the delivery’s own transaction by
the lease it holds: a lease lost meanwhile rolls everything back and the settlement fails with
SqlxBrokerError::LeaseLost. In the advisory lock form
the transaction runs on the session that holds the key, and ends before the key’s release. A
delivery dropped unsettled closes its transaction’s connection, and the server rolls the
transaction back.
§Examples
use std::time::Duration;
use ruststream_sqlx::prelude::*;
use serde::Deserialize;
use sqlx::PgPool;
#[derive(Inbox, sqlx::FromRow)]
#[inbox(table = "email_jobs")]
pub struct SendEmail {
#[field(id, generated)]
job_id: i64,
#[field(payload)]
payload: Vec<u8>,
}
#[derive(Deserialize)]
struct Email {
to: String,
}
// Each claimed row reaches `send` as an `InboxDelivery<Postgres, SendEmail>`, and what the
// handler returns settles it.
#[subscriber(InboxQueue::<SendEmail>::new("emails"))]
async fn send(email: &Email) -> HandlerOutcome {
match deliver(email).await {
Sent::Yes => HandlerOutcome::ack(),
// The mail server asked to come back later: the row returns once the minute passed.
Sent::Later => HandlerOutcome::retry_after(Duration::from_secs(60)),
// The address does not exist: the row is finished without a send.
Sent::Never => HandlerOutcome::drop(),
}
}
pub fn app(pool: PgPool) -> RustStream {
RustStream::new(AppInfo::new("mailer", "0.1.0")).with_broker(SqlxBroker::new(pool), |b| {
b.include(send);
})
}In row mode the handler borrows the row the delivery holds, beside what it reads off the delivery:
use ruststream_sqlx::prelude::*;
use sqlx::PgPool;
/// A mail to send: the table has no payload column, so a handler takes the row itself.
#[derive(Inbox, sqlx::FromRow, Clone)]
#[inbox(table = "mail_jobs")]
pub struct SendEmail {
#[field(id, generated)]
job_id: i64,
#[field(attempt, generated)]
attempt: i16,
to: String,
}
// The delivery lends `send` its row and reports the attempt the table counted.
#[subscriber(InboxQueue::<SendEmail>::new("mail"))]
async fn send(email: &SendEmail, Ctx(attempt): Ctx<keys::Attempt>) -> HandlerOutcome {
if deliver(&email.to).await {
HandlerOutcome::ack()
} else if attempt < Some(3) {
HandlerOutcome::retry()
} else {
HandlerOutcome::drop()
}
}
pub fn app(pool: PgPool) -> RustStream {
RustStream::new(AppInfo::new("mailer", "0.1.0")).with_broker(SqlxBroker::new(pool), |b| {
b.include(send);
})
}Trait Implementations§
Source§impl<DB, Row, Mode> BuildContext<InboxDelivery<DB, Row, Mode>> for PoolContext<DB>where
DB: QueueDatabase,
Row: Events<DB>,
Mode: InboxMode,
impl<DB, Row, Mode> BuildContext<InboxDelivery<DB, Row, Mode>> for PoolContext<DB>where
DB: QueueDatabase,
Row: Events<DB>,
Mode: InboxMode,
Source§fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self
fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self
msg.Source§impl<DB, Row, Mode> BuildContext<InboxDelivery<DB, Row, Mode>> for TxContext<DB>where
DB: QueueDatabase,
Row: Events<DB>,
InboxDelivery<DB, Row, Mode>: TransactionalDelivery<DB>,
impl<DB, Row, Mode> BuildContext<InboxDelivery<DB, Row, Mode>> for TxContext<DB>where
DB: QueueDatabase,
Row: Events<DB>,
InboxDelivery<DB, Row, Mode>: TransactionalDelivery<DB>,
Source§fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self
fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self
msg.Source§impl<DB, Row, Mode> Carries<Row> for InboxDelivery<DB, Row, Mode>where
DB: QueueDatabase,
Row: Events<DB> + QueueRow<Lane = RowLane>,
Mode: InboxMode,
impl<DB, Row, Mode> Carries<Row> for InboxDelivery<DB, Row, Mode>where
DB: QueueDatabase,
Row: Events<DB> + QueueRow<Lane = RowLane>,
Mode: InboxMode,
Source§impl<DB: QueueDatabase, Row: Events<DB>, Mode> Debug for InboxDelivery<DB, Row, Mode>
impl<DB: QueueDatabase, Row: Events<DB>, Mode> Debug for InboxDelivery<DB, Row, Mode>
Source§impl<DB: QueueDatabase, Row: Events<DB>, Mode> Drop for InboxDelivery<DB, Row, Mode>
impl<DB: QueueDatabase, Row: Events<DB>, Mode> Drop for InboxDelivery<DB, Row, Mode>
Source§impl<DB, Row, Mode> IncomingMessage for InboxDelivery<DB, Row, Mode>where
DB: QueueDatabase,
Row: Events<DB>,
Mode: InboxMode,
impl<DB, Row, Mode> IncomingMessage for InboxDelivery<DB, Row, Mode>where
DB: QueueDatabase,
Row: Events<DB>,
Mode: InboxMode,
Source§fn decode_error(&self) -> Option<&CodecError>
fn decode_error(&self) -> Option<&CodecError>
None when it read the delivery
whole. Read moreSource§fn partition_key(&self) -> Option<&[u8]>
fn partition_key(&self) -> Option<&[u8]>
None when the
message carries no key. Read moreSource§fn redelivery_count(&self) -> Option<u64>
fn redelivery_count(&self) -> Option<u64>
None
where the transport counts nothing. Read moreSource§async fn ack(self) -> Result<(), AckError>
async fn ack(self) -> Result<(), AckError>
Source§async fn nack(self, requeue: bool) -> Result<(), AckError>
async fn nack(self, requeue: bool) -> Result<(), AckError>
requeue is true the broker should
redeliver according to its own retry policy; when false it should drop or dead-letter
the message. Read moreSource§fn supports_nack_after(&self) -> bool
fn supports_nack_after(&self) -> bool
nack_after natively. Read moreAuto Trait Implementations§
impl<DB, Row, Mode = Plain> !RefUnwindSafe for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode = Plain> !UnwindSafe for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode> Freeze for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode> Send for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode> Sync for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode> Unpin for InboxDelivery<DB, Row, Mode>
impl<DB, Row, Mode> UnsafeUnpin for InboxDelivery<DB, Row, Mode>where
Claimed<Row>: UnsafeUnpin,
<Row as Events<DB>>::Headers: UnsafeUnpin,
Option<Hold<DB, Row>>: UnsafeUnpin,
&'static ServicePool<DB>: UnsafeUnpin,
<<Row as QueueRow>::Lane as Lane<Row>>::Lent: UnsafeUnpin,
Option<Arc<Shared<DB>>>: UnsafeUnpin,
PhantomData<fn() -> Mode>: 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