use std::time::Duration;
pub struct LockService;
impl LockService {
pub async fn acquire(key: i64, pool: &sqlx::PgPool) -> Result<(), sqlx::Error> {
sqlx::query("SELECT pg_advisory_lock($1)")
.bind(key)
.execute(pool)
.await?;
Ok(())
}
pub async fn try_acquire(key: i64, pool: &sqlx::PgPool) -> Result<bool, sqlx::Error> {
let row: (bool,) = sqlx::query_as("SELECT pg_try_advisory_lock($1)")
.bind(key)
.fetch_one(pool)
.await?;
Ok(row.0)
}
pub async fn release(key: i64, pool: &sqlx::PgPool) -> Result<(), sqlx::Error> {
sqlx::query("SELECT pg_advisory_unlock($1)")
.bind(key)
.execute(pool)
.await?;
Ok(())
}
pub async fn acquire_timeout(
key: i64,
timeout: Duration,
pool: &sqlx::PgPool,
) -> Result<bool, sqlx::Error> {
let start = std::time::Instant::now();
loop {
if LockService::try_acquire(key, pool).await? {
return Ok(true);
}
if start.elapsed() >= timeout {
return Ok(false);
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
}
pub async fn acquire_xact(key: i64, pool: &sqlx::PgPool) -> Result<(), sqlx::Error> {
sqlx::query("SELECT pg_advisory_xact_lock($1)")
.bind(key)
.execute(pool)
.await?;
Ok(())
}
pub async fn try_acquire_xact(key: i64, pool: &sqlx::PgPool) -> Result<bool, sqlx::Error> {
let row: (bool,) = sqlx::query_as("SELECT pg_try_advisory_xact_lock($1)")
.bind(key)
.fetch_one(pool)
.await?;
Ok(row.0)
}
}