gitdataai/lib/git/sync/lock.rs
2026-05-30 01:38:40 +08:00

59 lines
1.6 KiB
Rust

use deadpool_redis::cluster::Pool as RedisPool;
pub async fn acquire_repo_lock(
pool: &RedisPool,
repo_id: uuid::Uuid,
lock_value: &str,
ttl_secs: usize,
) -> redis::RedisResult<bool> {
let lock_key = format!("git:repo:lock:{}", repo_id);
let redis = pool.get().await.map_err(|e| {
redis::RedisError::from((
redis::ErrorKind::Io,
"failed to get Redis connection",
e.to_string(),
))
})?;
let mut conn: deadpool_redis::cluster::Connection = redis;
let acquired: Option<String> = redis::cmd("SET")
.arg(&lock_key)
.arg(lock_value)
.arg("NX")
.arg("EX")
.arg(ttl_secs)
.query_async(&mut conn)
.await?;
Ok(acquired.is_some())
}
pub async fn release_repo_lock(
pool: &RedisPool,
repo_id: uuid::Uuid,
lock_value: &str,
) {
let lock_key = format!("git:repo:lock:{}", repo_id);
let redis = match pool.get().await {
Ok(c) => c,
Err(e) => {
tracing::warn!(error = %e, repo_id = %repo_id, "lock_release_redis_connection_failed");
return;
}
};
let mut conn: deadpool_redis::cluster::Connection = redis;
let script = redis::Script::new(
r#"
if redis.call("GET", KEYS[1]) == ARGV[1] then
redis.call("DEL", KEYS[1])
return 1
end
return 0
"#,
);
if let Err(e) = script
.key(&lock_key)
.arg(lock_value)
.invoke_async::<i32>(&mut conn)
.await
{
tracing::warn!(error = %e, repo_id = %repo_id, "lock_release_failed");
}
}