pub struct Tx<DB: QueueDatabase> { /* private fields */ }Expand description
The delivery’s transaction, lent to the handler: it dereferences to the connection the transaction runs on, and goes back to the delivery when the handler ends.
A handler takes it as its first Ctx parameter, Ctx(mut tx): Ctx<keys::Tx<DB>>, on a
registration mounted with transactional. It writes
through &mut *tx, as through the connection of a sqlx transaction, and (&mut *tx).begin()
nests a savepoint of its own. The delivery’s settlement ends the transaction: acknowledgement
commits it, every other outcome rolls the handler’s writes back first. Dropping Tx gives the
transaction back and ends nothing. A Tx dropped by a panic marks the handler’s writes for
the rollback, so a delivery acknowledged after its handler panicked, as the skip panic policy
does, commits none of them.
Tx is an owned value, so a handler may move it into a task of its own. The transaction must
be back when the delivery settles: a settlement that finds it still lent fails with
SqlxBrokerError::TransactionHeld, and the
transaction rolls back when that Tx drops.
§Examples
use ruststream_sqlx::prelude::*;
use sqlx::{PgPool, Postgres};
#[derive(Inbox, sqlx::FromRow)]
#[inbox(table = "payment_jobs")]
pub struct PaymentJob {
#[field(id)]
id: i64,
#[field(payload)]
payload: Vec<u8>,
}
#[derive(serde::Deserialize)]
struct Payment {
account: String,
cents: i64,
}
#[subscriber(InboxQueue::<PaymentJob>::new("payments"))]
async fn post(payment: &Payment, Ctx(mut tx): Ctx<keys::Tx<Postgres>>) -> HandlerOutcome {
let posted = sqlx::query("INSERT INTO ledger (account, cents) VALUES ($1, $2)")
.bind(&payment.account)
.bind(payment.cents)
.execute(&mut *tx)
.await;
match posted {
// The commit keeps the ledger row and finishes the job, together.
Ok(_) => HandlerOutcome::ack(),
// The retry discards the ledger row and returns the job to the queue.
Err(error) => {
tracing::warn!(%error, "the payment was not posted");
HandlerOutcome::retry()
}
}
}
pub fn app(pool: PgPool) -> RustStream {
RustStream::new(AppInfo::new("payments", "0.1.0")).with_broker(SqlxBroker::new(pool), |b| {
b.include(post.transactional());
})
}Trait Implementations§
Source§impl<DB: QueueDatabase> AsMut<<DB as Database>::Connection> for Tx<DB>
impl<DB: QueueDatabase> AsMut<<DB as Database>::Connection> for Tx<DB>
Source§fn as_mut(&mut self) -> &mut DB::Connection
fn as_mut(&mut self) -> &mut DB::Connection
Source§impl<DB: QueueDatabase> Debug for Tx<DB>
impl<DB: QueueDatabase> Debug for Tx<DB>
Source§impl<DB: QueueDatabase> Deref for Tx<DB>
impl<DB: QueueDatabase> Deref for Tx<DB>
Source§fn deref(&self) -> &DB::Connection
fn deref(&self) -> &DB::Connection
The connection inside the delivery’s transaction.
§Panics
Never: Tx holds the transaction until it drops.
Source§type Target = <DB as Database>::Connection
type Target = <DB as Database>::Connection
Source§impl<DB: QueueDatabase> DerefMut for Tx<DB>
impl<DB: QueueDatabase> DerefMut for Tx<DB>
Source§fn deref_mut(&mut self) -> &mut DB::Connection
fn deref_mut(&mut self) -> &mut DB::Connection
The connection inside the delivery’s transaction, to run a statement on.
§Panics
Never: Tx holds the transaction until it drops.
Source§impl<DB: QueueDatabase> Drop for Tx<DB>
impl<DB: QueueDatabase> Drop for Tx<DB>
Auto Trait Implementations§
impl<DB> !RefUnwindSafe for Tx<DB>
impl<DB> !UnwindSafe for Tx<DB>
impl<DB> Freeze for Tx<DB>
impl<DB> Send for Tx<DB>
impl<DB> Sync for Tx<DB>
impl<DB> Unpin for Tx<DB>
impl<DB> UnsafeUnpin for Tx<DB>where
Option<Lent<DB>>: 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
impl<R> CryptoRng for R
impl<T> Formattable for 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 moreimpl<T> Parsable for T
impl<T> PublishedThrough<DefaultSlot> for T
impl<R> RngCore for Rwhere
R: Rng,
Source§impl<R> RngExt for R
impl<R> RngExt for R
Source§fn random<T>(&mut self) -> Twhere
StandardUniform: Distribution<T>,
fn random<T>(&mut self) -> Twhere
StandardUniform: Distribution<T>,
StandardUniform distribution. Read moreSource§fn random_iter<T>(self) -> Iter<StandardUniform, Self, T> ⓘ
fn random_iter<T>(self) -> Iter<StandardUniform, Self, T> ⓘ
Source§fn random_range<T, R>(&mut self, range: R) -> Twhere
T: SampleUniform,
R: SampleRange<T>,
fn random_range<T, R>(&mut self, range: R) -> Twhere
T: SampleUniform,
R: SampleRange<T>,
Source§fn random_bool(&mut self, p: f64) -> bool
fn random_bool(&mut self, p: f64) -> bool
p of being true. Read moreSource§fn random_ratio(&mut self, numerator: u32, denominator: u32) -> bool
fn random_ratio(&mut self, numerator: u32, denominator: u32) -> bool
numerator/denominator of being
true. Read more