use sqlx_core::transaction::TransactionManager;
use super::session::Session;
use super::{LockHold, Locked};
use crate::inbox::database::QueueDatabase;
use crate::inbox::delivery::settle::{Step, run_step};
use crate::inbox::engine::{Events, Settled, Settling};
use crate::inbox::transactional::settle::settle_in_session;
pub(crate) async fn settle_advised<DB, Row>(
hold: LockHold<DB>,
mut lent: Locked<'static, DB>,
panicked: bool,
cx: &Settling,
id: &Row::Id,
step: Step,
) -> Result<Settled, sqlx::Error>
where
DB: QueueDatabase,
Row: Events<DB>,
{
let settled = if cx.queue.prepared.transactional {
settle_in_session::<DB, Row>(lent.session(), cx, id, step, panicked).await
} else {
run_advised::<DB, Row>(lent.session(), cx, id, step).await
};
if hold.book().process() {
lent.session().free_in_process();
} else {
let unlocked = {
let (conn, key) = lent.conn_and_key();
Row::unlock(conn, cx, key).await
};
let key = lent.key();
match unlocked {
Ok(true) => lent.session().set_locked(false),
Ok(false) => tracing::warn!(
target: "ruststream_sqlx",
subscription = cx.queue.name,
table = cx.queue.table,
row = cx.queue.row,
?id,
key,
"a settlement's unlock found the session not holding the row's key; the session \
closes",
),
Err(error) => tracing::warn!(
target: "ruststream_sqlx",
subscription = cx.queue.name,
table = cx.queue.table,
row = cx.queue.row,
?id,
key,
%error,
"a settlement's unlock failed; the session closes, which ends its lock",
),
}
}
let (session, key) = lent.into_parts();
session.release();
hold.leave(key.into_owned());
settled
}
pub(crate) async fn run_advised<DB, Row>(
session: &mut Session<DB>,
cx: &Settling,
id: &Row::Id,
step: Step,
) -> Result<Settled, sqlx::Error>
where
DB: QueueDatabase,
Row: Events<DB>,
{
let split = matches!(step, Step::DeadLetter(_)) && cx.queue.prepared.dead_letter_then.is_some();
if !split {
return run_step::<DB, Row>(session.conn(), cx, id, None, step).await;
}
session.set_open(true);
DB::TransactionManager::begin(session.conn(), None).await?;
match run_step::<DB, Row>(session.conn(), cx, id, None, step).await {
Ok(settled) => {
DB::TransactionManager::commit(session.conn()).await?;
session.set_open(false);
Ok(settled)
}
Err(error) => {
if DB::TransactionManager::rollback(session.conn())
.await
.is_ok()
{
session.set_open(false);
}
Err(error)
}
}
}