refactor(storage_impl): split payment attempt models to domain + diesel (#2010)

Signed-off-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com>
Co-authored-by: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com>
Co-authored-by: Arjun Karthik <m.arjunkarthik@gmail.com>
Co-authored-by: Sai Harsha Vardhan <56996463+sai-harsha-vardhan@users.noreply.github.com>
Co-authored-by: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com>
Co-authored-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com>
Co-authored-by: Prasunna Soppa <prasunna.soppa@juspay.in>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com>
Co-authored-by: Arvind Patel <52006565+arvindpatel24@users.noreply.github.com>
Co-authored-by: Jagan Elavarasan <jaganelavarasan@gmail.com>
Co-authored-by: arvindpatel24 <arvind.patel@juspay.in>
Co-authored-by: anji-reddy-j <125157119+anji-reddy-j@users.noreply.github.com>
Co-authored-by: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com>
Co-authored-by: Apoorv Dixit <64925866+apoorvdixit88@users.noreply.github.com>
Co-authored-by: Pa1NarK <69745008+pixincreate@users.noreply.github.com>
This commit is contained in:
Sampras Lopes
2023-09-11 17:33:47 +05:30
committed by GitHub
parent 25e82a1f7f
commit ad4b7de628
57 changed files with 2362 additions and 1546 deletions

View File

@ -1,11 +1,19 @@
use std::{any::Any, borrow::Cow, sync::Arc};
use common_utils::errors;
use common_utils::{
errors::{self, CustomResult},
ext_traits::AsyncExt,
};
use data_models::errors::StorageError;
use dyn_clone::DynClone;
use error_stack::Report;
use error_stack::{Report, ResultExt};
use moka::future::Cache as MokaCache;
use once_cell::sync::Lazy;
use redis_interface::RedisValue;
use redis_interface::{errors::RedisError, RedisValue};
use super::{kv_store::RedisConnInterface, pub_sub::PubSubInterface};
pub(crate) const PUB_SUB_CHANNEL: &str = "hyperswitch_invalidate";
/// Prefix for config cache key
const CONFIG_CACHE_PREFIX: &str = "config";
@ -128,6 +136,127 @@ impl Cache {
}
}
pub async fn get_or_populate_redis<T, F, Fut>(
store: &(dyn RedisConnInterface + Send + Sync),
key: &str,
fun: F,
) -> CustomResult<T, StorageError>
where
T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug,
F: FnOnce() -> Fut + Send,
Fut: futures::Future<Output = CustomResult<T, StorageError>> + Send,
{
let type_name = std::any::type_name::<T>();
let redis = &store
.get_redis_conn()
.map_err(|er| {
let error = format!("{}", er);
er.change_context(StorageError::RedisError(error))
})
.attach_printable("Failed to get redis connection")?;
let redis_val = redis.get_and_deserialize_key::<T>(key, type_name).await;
let get_data_set_redis = || async {
let data = fun().await?;
redis
.serialize_and_set_key(key, &data)
.await
.change_context(StorageError::KVError)?;
Ok::<_, Report<StorageError>>(data)
};
match redis_val {
Err(err) => match err.current_context() {
RedisError::NotFound | RedisError::JsonDeserializationFailed => {
get_data_set_redis().await
}
_ => Err(err
.change_context(StorageError::KVError)
.attach_printable(format!("Error while fetching cache for {type_name}"))),
},
Ok(val) => Ok(val),
}
}
pub async fn get_or_populate_in_memory<T, F, Fut>(
store: &(dyn RedisConnInterface + Send + Sync),
key: &str,
fun: F,
cache: &Cache,
) -> CustomResult<T, StorageError>
where
T: Cacheable + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone,
F: FnOnce() -> Fut + Send,
Fut: futures::Future<Output = CustomResult<T, StorageError>> + Send,
{
let cache_val = cache.get_val::<T>(key);
if let Some(val) = cache_val {
Ok(val)
} else {
let val = get_or_populate_redis(store, key, fun).await?;
cache.push(key.to_string(), val.clone()).await;
Ok(val)
}
}
pub async fn redact_cache<T, F, Fut>(
store: &dyn RedisConnInterface,
key: &str,
fun: F,
in_memory: Option<&Cache>,
) -> CustomResult<T, StorageError>
where
F: FnOnce() -> Fut + Send,
Fut: futures::Future<Output = CustomResult<T, StorageError>> + Send,
{
let data = fun().await?;
in_memory.async_map(|cache| cache.invalidate(key)).await;
let redis_conn = store
.get_redis_conn()
.map_err(|er| {
let error = format!("{}", er);
er.change_context(StorageError::RedisError(error))
})
.attach_printable("Failed to get redis connection")?;
redis_conn
.delete_key(key)
.await
.change_context(StorageError::KVError)?;
Ok(data)
}
pub async fn publish_into_redact_channel<'a>(
store: &dyn RedisConnInterface,
key: CacheKind<'a>,
) -> CustomResult<usize, StorageError> {
let redis_conn = store
.get_redis_conn()
.map_err(|er| {
let error = format!("{}", er);
er.change_context(StorageError::RedisError(error))
})
.attach_printable("Failed to get redis connection")?;
redis_conn
.publish(PUB_SUB_CHANNEL, key)
.await
.change_context(StorageError::KVError)
}
pub async fn publish_and_redact<'a, T, F, Fut>(
store: &dyn RedisConnInterface,
key: CacheKind<'a>,
fun: F,
) -> CustomResult<T, StorageError>
where
F: FnOnce() -> Fut + Send,
Fut: futures::Future<Output = CustomResult<T, StorageError>> + Send,
{
let data = fun().await?;
publish_into_redact_channel(store, key).await?;
Ok(data)
}
#[cfg(test)]
mod cache_tests {
use super::*;