pub trait Lock<DB: Database>: InboxRow {
// Required method
fn lock(
conn: &mut DB::Connection,
key: &str,
) -> impl Future<Output = Result<bool, Error>> + Send;
}Expand description
Takes the advisory lock on a row’s key for the session that will hold its delivery, without
waiting: the lock event of the advisory lock form.
The dialect takes the lock itself on Postgres and MySQL, and the process keeps the keys in work
on SQLite. A table names lock and unlock as its own together (custom(lock, unlock), or
own::Lock and own::Unlock by hand) to
run the service’s own SQL for them instead, as a database without a built-in dialect does, MSSQL with
sp_getapplock and sp_releaseapplock; the dialect still selects the candidates and takes
each row. A claim calls it once per candidate with the key the template renders, on the
connection that holds the delivery; Unlock releases the lock when the delivery settles,
and where the delivery is dropped unsettled the connection closes after that unlock. With a
lock of the service’s own the process keeps no registry of keys, on SQLite too.
The dialect’s candidate select cannot see a lock of the service’s own, so a claim reads as many candidates past its limit as the subscription has deliveries in work: a key its deliveries hold does not hold back the rows behind it. A key the service’s lock holds elsewhere, in another process or system, is passed over within that margin only: while such keys head the claim order, the claim may end empty and wait for its next poll.
§Examples
use ruststream_sqlx::{Inbox, Lock, Unlock};
use sqlx::{PgConnection, Postgres};
#[derive(Inbox, sqlx::FromRow)]
#[inbox(table = "jobs", advisory_lock = "jobs-{id}", custom(lock, unlock))]
pub struct Job {
#[field(id)]
id: i64,
#[field(payload)]
payload: Vec<u8>,
}
// The pair MSSQL writes with `sp_getapplock` and `sp_releaseapplock`, written here with
// Postgres's session locks on a 32-bit hash of the key.
impl Lock<Postgres> for Job {
async fn lock(conn: &mut PgConnection, key: &str) -> Result<bool, sqlx::Error> {
sqlx::query_scalar("SELECT pg_try_advisory_lock(hashtext($1))")
.bind(key)
.fetch_one(conn)
.await
}
}
impl Unlock<Postgres> for Job {
async fn unlock(conn: &mut PgConnection, key: &str) -> Result<bool, sqlx::Error> {
sqlx::query_scalar("SELECT pg_advisory_unlock(hashtext($1))")
.bind(key)
.fetch_one(conn)
.await
}
}Required Methods§
Sourcefn lock(
conn: &mut DB::Connection,
key: &str,
) -> impl Future<Output = Result<bool, Error>> + Send
fn lock( conn: &mut DB::Connection, key: &str, ) -> impl Future<Output = Result<bool, Error>> + Send
Tries the advisory lock on key for the session of conn, without waiting: true when it
took the lock. The session holds it until Unlock releases it or the session ends.
§Errors
The database’s error; the claim fails, its connection closes, and the next claim waits one second.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".