use crate::cache_redis::{RedisCacheError, RedisCacheResult, RedisLuaScript};
use super::RedisDistributedLock;
impl RedisDistributedLock {
pub(crate) async fn invoke_release_script<C>(
&self,
connection: &mut C,
keys: &[String],
args: &[String],
) -> RedisCacheResult<i64>
where
C: redis::aio::ConnectionLike + Send,
{
match self.eval_release_script(connection, keys, args).await {
Ok(value) => Ok(value),
Err(error) if RedisLuaScript::is_noscript_error(&error) => {
self.load_release_script(connection).await?;
self.eval_release_script(connection, keys, args).await
}
Err(error) => Err(error),
}
}
async fn load_release_script<C>(&self, connection: &mut C) -> RedisCacheResult<String>
where
C: redis::aio::ConnectionLike + Send,
{
tokio::time::timeout(self.config.command_timeout, async {
redis::cmd("SCRIPT")
.arg("LOAD")
.arg(self.release_script.text().as_bytes())
.query_async::<String>(connection)
.await
})
.await
.map_err(|_| RedisCacheError::Timeout("SCRIPT LOAD".to_string()))?
.map_err(crate::cache_redis::redis_error)
}
async fn eval_release_script<C>(
&self,
connection: &mut C,
keys: &[String],
args: &[String],
) -> RedisCacheResult<i64>
where
C: redis::aio::ConnectionLike + Send,
{
let mut cmd = redis::cmd("EVALSHA");
cmd.arg(self.release_script.sha1()).arg(keys.len());
for key in keys {
cmd.arg(key);
}
for arg in args {
cmd.arg(arg);
}
tokio::time::timeout(self.config.command_timeout, async {
cmd.query_async::<i64>(connection).await
})
.await
.map_err(|_| RedisCacheError::Timeout("EVALSHA".to_string()))?
.map_err(crate::cache_redis::redis_error)
}
}