Skip to main content

InboxDelivery

Struct InboxDelivery 

Source
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,

Source§

fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self

Builds the context value by reading fields out of 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>,

Source§

fn build(msg: &InboxDelivery<DB, Row, Mode>) -> Self

Builds the context value by reading fields out of msg.
Source§

impl<DB, Row, Mode> Carries<Row> for InboxDelivery<DB, Row, Mode>
where DB: QueueDatabase, Row: Events<DB> + QueueRow<Lane = RowLane>, Mode: InboxMode,

Source§

fn carried(&self) -> Option<&Row>

The value this delivery holds, or None where it has none.
Source§

impl<DB: QueueDatabase, Row: Events<DB>, Mode> Debug for InboxDelivery<DB, Row, Mode>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<DB: QueueDatabase, Row: Events<DB>, Mode> Drop for InboxDelivery<DB, Row, Mode>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<DB, Row, Mode> IncomingMessage for InboxDelivery<DB, Row, Mode>
where DB: QueueDatabase, Row: Events<DB>, Mode: InboxMode,

Source§

fn payload(&self) -> &[u8] ⓘ

Returns the raw payload of the message.
Source§

fn headers(&self) -> &HeaderMap

Returns the headers attached to the message.
Source§

fn decode_error(&self) -> Option<&CodecError>

The error the broker met while reading this delivery, or None when it read the delivery whole. Read more
Source§

fn partition_key(&self) -> Option<&[u8]>

Returns the routing key the broker partitioned this message by, or None when the message carries no key. Read more
Source§

fn redelivery_count(&self) -> Option<u64>

How many times the broker has delivered this message, counting this delivery. None where the transport counts nothing. Read more
Source§

async fn ack(self) -> Result<(), AckError>

Acknowledges successful processing. Consumes the message handle. Read more
Source§

async fn nack(self, requeue: bool) -> Result<(), AckError>

Negatively acknowledges the message. When requeue is true the broker should redeliver according to its own retry policy; when false it should drop or dead-letter the message. Read more
Source§

fn supports_nack_after(&self) -> bool

Reports whether this transport can honor nack_after natively. Read more
Source§

async fn nack_after(self, delay: Duration) -> Result<(), AckError>

Negatively acknowledges the message, asking the broker to redeliver it no sooner than delay from now. Read more

Auto 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>
where Claimed<Row>: Freeze, <Row as Events<DB>>::Headers: Freeze, Option<Hold<DB, Row>>: Freeze, &'static ServicePool<DB>: Freeze, <<Row as QueueRow>::Lane as Lane<Row>>::Lent: Freeze, Option<Arc<Shared<DB>>>: Freeze, PhantomData<fn() -> Mode>: Freeze,

§

impl<DB, Row, Mode> Send for InboxDelivery<DB, Row, Mode>
where Claimed<Row>: Send, <Row as Events<DB>>::Headers: Send, Option<Hold<DB, Row>>: Send, &'static ServicePool<DB>: Send, <<Row as QueueRow>::Lane as Lane<Row>>::Lent: Send, Option<Arc<Shared<DB>>>: Send, PhantomData<fn() -> Mode>: Send,

§

impl<DB, Row, Mode> Sync for InboxDelivery<DB, Row, Mode>
where Claimed<Row>: Sync, <Row as Events<DB>>::Headers: Sync, Option<Hold<DB, Row>>: Sync, &'static ServicePool<DB>: Sync, <<Row as QueueRow>::Lane as Lane<Row>>::Lent: Sync, Option<Arc<Shared<DB>>>: Sync, PhantomData<fn() -> Mode>: Sync,

§

impl<DB, Row, Mode> Unpin for InboxDelivery<DB, Row, Mode>
where Claimed<Row>: Unpin, <Row as Events<DB>>::Headers: Unpin, Option<Hold<DB, Row>>: Unpin, &'static ServicePool<DB>: Unpin, <<Row as QueueRow>::Lane as Lane<Row>>::Lent: Unpin, Option<Arc<Shared<DB>>>: Unpin, PhantomData<fn() -> Mode>: Unpin,

§

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> PublishedThrough<DefaultSlot> for T

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more