feat(redis-interface): add redis interface command to set multiple the keys in redis and increment if the key already exists (#6827)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Nishant Joshi <nishant.joshi@juspay.in>
This commit is contained in:
Amisha Prabhat
2024-12-17 15:52:31 +05:30
committed by GitHub
parent 886e2aacd7
commit 94ad90f9ed

View File

@ -14,7 +14,7 @@ use common_utils::{
use error_stack::{report, ResultExt};
use fred::{
interfaces::{HashesInterface, KeysInterface, ListInterface, SetsInterface, StreamsInterface},
prelude::RedisErrorKind,
prelude::{LuaInterface, RedisErrorKind},
types::{
Expiration, FromRedis, MultipleIDs, MultipleKeys, MultipleOrderedPairs, MultipleStrings,
MultipleValues, RedisKey, RedisMap, RedisValue, ScanType, Scanner, SetOptions, XCap,
@ -852,12 +852,31 @@ impl super::RedisConnectionPool {
.await
.change_context(errors::RedisError::ConsumerGroupClaimFailed)
}
#[instrument(level = "DEBUG", skip(self))]
pub async fn incr_keys_using_script<V>(
&self,
lua_script: &'static str,
key: Vec<String>,
values: V,
) -> CustomResult<(), errors::RedisError>
where
V: TryInto<MultipleValues> + Debug + Send + Sync,
V::Error: Into<fred::error::RedisError> + Send + Sync,
{
self.pool
.eval(lua_script, key, values)
.await
.change_context(errors::RedisError::IncrementHashFieldFailed)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use std::collections::HashMap;
use crate::{errors::RedisError, RedisConnectionPool, RedisEntryId, RedisSettings};
#[tokio::test]
@ -911,7 +930,6 @@ mod tests {
assert!(is_success);
}
#[tokio::test]
async fn test_delete_non_existing_key_success() {
let is_success = tokio::task::spawn_blocking(move || {
@ -930,6 +948,44 @@ mod tests {
})
.await
.expect("Spawn block failure");
assert!(is_success);
}
#[tokio::test]
async fn test_setting_keys_using_scripts() {
let is_success = tokio::task::spawn_blocking(move || {
futures::executor::block_on(async {
// Arrange
let pool = RedisConnectionPool::new(&RedisSettings::default())
.await
.expect("failed to create redis connection pool");
let lua_script = r#"
local results = {}
for i = 1, #KEYS do
results[i] = redis.call("INCRBY", KEYS[i], ARGV[i])
end
return results
"#;
let mut keys_and_values = HashMap::new();
for i in 0..10 {
keys_and_values.insert(format!("key{}", i), i);
}
let key = keys_and_values.keys().cloned().collect::<Vec<_>>();
let values = keys_and_values
.values()
.map(|val| val.to_string())
.collect::<Vec<String>>();
// Act
let result = pool.incr_keys_using_script(lua_script, key, values).await;
// Assert Setup
result.is_ok()
})
})
.await
.expect("Spawn block failure");
assert!(is_success);
}