use crate::GitError; use crate::hook::sync::HookMetaDataSync; impl HookMetaDataSync { const LOCK_TTL_SECS: u64 = 60; pub async fn acquire_lock(&self) -> Result { let lock_key = format!("git:repo:lock:{}", self.repo.id); let lock_value = format!("{}:{}", uuid::Uuid::new_v4(), std::process::id()); let mut conn = self .cache .conn() .await .map_err(|e| GitError::IoError(format!("failed to get redis connection: {}", e)))?; let result: bool = redis::cmd("SET") .arg(&lock_key) .arg(&lock_value) .arg("NX") .arg("EX") .arg(Self::LOCK_TTL_SECS) .query_async(&mut conn) .await .map_err(|e| GitError::IoError(format!("failed to acquire lock: {}", e)))?; if result { Ok(lock_value) } else { Err(GitError::Locked(format!( "repository {} is locked by another process", self.repo.id ))) } } pub async fn release_lock(&self, lock_value: &str) -> Result<(), GitError> { let lock_key = format!("git:repo:lock:{}", self.repo.id); let mut conn = self .cache .conn() .await .map_err(|e| GitError::IoError(format!("failed to get redis connection: {}", e)))?; let script = r#" if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end "#; let _: i32 = redis::Script::new(script) .key(&lock_key) .arg(lock_value) .invoke_async(&mut conn) .await .map_err(|e| GitError::IoError(format!("failed to release lock: {}", e)))?; Ok(()) } }