mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
fix(redis_interface): fix derps in HSET and HSETNX command wrappers (#129)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1292,7 +1292,6 @@ dependencies = [
|
||||
"rand",
|
||||
"redis-protocol",
|
||||
"semver",
|
||||
"serde_json",
|
||||
"sha-1",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
|
||||
@ -9,7 +9,7 @@ license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
error-stack = "0.2.4"
|
||||
fred = { version = "5.2.0", features = ["metrics", "partial-tracing", "serde-json"] }
|
||||
fred = { version = "5.2.0", features = ["metrics", "partial-tracing"] }
|
||||
serde = { version = "1.0.149", features = ["derive"] }
|
||||
thiserror = "1.0.37"
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ use router_env::{tracing, tracing::instrument};
|
||||
|
||||
use crate::{
|
||||
errors,
|
||||
types::{RedisEntryId, SetNXReply},
|
||||
types::{HsetnxReply, RedisEntryId, SetnxReply},
|
||||
};
|
||||
|
||||
impl super::RedisConnectionPool {
|
||||
@ -142,7 +142,7 @@ impl super::RedisConnectionPool {
|
||||
&self,
|
||||
key: &str,
|
||||
value: V,
|
||||
) -> CustomResult<SetNXReply, errors::RedisError>
|
||||
) -> CustomResult<SetnxReply, errors::RedisError>
|
||||
where
|
||||
V: TryInto<RedisValue> + Debug,
|
||||
V::Error: Into<fred::error::RedisError>,
|
||||
@ -203,28 +203,13 @@ impl super::RedisConnectionPool {
|
||||
.change_context(errors::RedisError::SetHashFailed)
|
||||
}
|
||||
|
||||
#[instrument(level = "DEBUG", skip(self))]
|
||||
pub async fn serialize_and_set_hash_fields<V>(
|
||||
&self,
|
||||
key: &str,
|
||||
values: V,
|
||||
) -> CustomResult<(), errors::RedisError>
|
||||
where
|
||||
V: serde::Serialize + Debug,
|
||||
{
|
||||
let serialized = Encode::<V>::encode_to_value(&values)
|
||||
.change_context(errors::RedisError::JsonSerializationFailed)?;
|
||||
|
||||
self.set_hash_fields(key, serialized).await
|
||||
}
|
||||
|
||||
#[instrument(level = "DEBUG", skip(self))]
|
||||
pub async fn set_hash_field_if_not_exist<V>(
|
||||
&self,
|
||||
key: &str,
|
||||
field: &str,
|
||||
value: V,
|
||||
) -> CustomResult<SetNXReply, errors::RedisError>
|
||||
) -> CustomResult<HsetnxReply, errors::RedisError>
|
||||
where
|
||||
V: TryInto<RedisValue> + Debug,
|
||||
V::Error: Into<fred::error::RedisError>,
|
||||
@ -242,7 +227,7 @@ impl super::RedisConnectionPool {
|
||||
key: &str,
|
||||
field: &str,
|
||||
value: V,
|
||||
) -> CustomResult<SetNXReply, errors::RedisError>
|
||||
) -> CustomResult<HsetnxReply, errors::RedisError>
|
||||
where
|
||||
V: serde::Serialize + Debug,
|
||||
{
|
||||
|
||||
@ -67,18 +67,18 @@ impl From<&RedisEntryId> for fred::types::XID {
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum SetNXReply {
|
||||
pub enum SetnxReply {
|
||||
KeySet,
|
||||
KeyNotSet, // Existing key
|
||||
}
|
||||
|
||||
impl fred::types::FromRedis for SetNXReply {
|
||||
impl fred::types::FromRedis for SetnxReply {
|
||||
fn from_value(value: fred::types::RedisValue) -> Result<Self, fred::error::RedisError> {
|
||||
match value {
|
||||
// Returns String ( "OK" ) in case of success
|
||||
fred::types::RedisValue::String(_) => Ok(SetNXReply::KeySet),
|
||||
fred::types::RedisValue::String(_) => Ok(Self::KeySet),
|
||||
// Return Null in case of failure
|
||||
fred::types::RedisValue::Null => Ok(SetNXReply::KeyNotSet),
|
||||
fred::types::RedisValue::Null => Ok(Self::KeyNotSet),
|
||||
// Unexpected behaviour
|
||||
_ => Err(fred::error::RedisError::new(
|
||||
fred::error::RedisErrorKind::Unknown,
|
||||
@ -87,3 +87,22 @@ impl fred::types::FromRedis for SetNXReply {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum HsetnxReply {
|
||||
KeySet,
|
||||
KeyNotSet, // Existing key
|
||||
}
|
||||
|
||||
impl fred::types::FromRedis for HsetnxReply {
|
||||
fn from_value(value: fred::types::RedisValue) -> Result<Self, fred::error::RedisError> {
|
||||
match value {
|
||||
fred::types::RedisValue::Integer(1) => Ok(Self::KeySet),
|
||||
fred::types::RedisValue::Integer(0) => Ok(Self::KeyNotSet),
|
||||
_ => Err(fred::error::RedisError::new(
|
||||
fred::error::RedisErrorKind::Unknown,
|
||||
"Unexpected HSETNX command reply",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ impl PaymentAttemptInterface for MockDb {
|
||||
mod storage {
|
||||
use common_utils::date_time;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use redis_interface::{RedisEntryId, SetNXReply};
|
||||
use redis_interface::{HsetnxReply, RedisEntryId};
|
||||
|
||||
use super::PaymentAttemptInterface;
|
||||
use crate::{
|
||||
@ -377,11 +377,11 @@ mod storage {
|
||||
.serialize_and_set_hash_field_if_not_exist(&key, "pa", &created_attempt)
|
||||
.await
|
||||
{
|
||||
Ok(SetNXReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
||||
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
||||
format!("Payment Attempt already exists for payment_id: {}", key),
|
||||
))
|
||||
.into_report(),
|
||||
Ok(SetNXReply::KeySet) => {
|
||||
Ok(HsetnxReply::KeySet) => {
|
||||
let conn = pg_connection(&self.master_pool).await;
|
||||
let query = payment_attempt
|
||||
.insert_query(&conn)
|
||||
@ -430,9 +430,12 @@ mod storage {
|
||||
|
||||
let updated_attempt = payment_attempt.clone().apply_changeset(this.clone());
|
||||
// Check for database presence as well Maybe use a read replica here ?
|
||||
let redis_value = serde_json::to_string(&updated_attempt)
|
||||
.into_report()
|
||||
.change_context(errors::StorageError::KVError)?;
|
||||
let updated_attempt = self
|
||||
.redis_conn
|
||||
.serialize_and_set_hash_fields(&key, ("pa", &updated_attempt))
|
||||
.set_hash_fields(&key, ("pa", &redis_value))
|
||||
.await
|
||||
.map(|_| updated_attempt)
|
||||
.change_context(errors::StorageError::KVError)?;
|
||||
|
||||
@ -41,7 +41,7 @@ pub trait PaymentIntentInterface {
|
||||
mod storage {
|
||||
use common_utils::date_time;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use redis_interface::{RedisEntryId, SetNXReply};
|
||||
use redis_interface::{HsetnxReply, RedisEntryId};
|
||||
|
||||
use super::PaymentIntentInterface;
|
||||
use crate::{
|
||||
@ -100,11 +100,11 @@ mod storage {
|
||||
.serialize_and_set_hash_field_if_not_exist(&key, "pi", &created_intent)
|
||||
.await
|
||||
{
|
||||
Ok(SetNXReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
||||
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
|
||||
format!("Payment Intent already exists for payment_id: {key}"),
|
||||
))
|
||||
.into_report(),
|
||||
Ok(SetNXReply::KeySet) => {
|
||||
Ok(HsetnxReply::KeySet) => {
|
||||
let conn = pg_connection(&self.master_pool).await;
|
||||
let query = new
|
||||
.insert_query(&conn)
|
||||
@ -153,9 +153,12 @@ mod storage {
|
||||
|
||||
let updated_intent = payment_intent.clone().apply_changeset(this.clone());
|
||||
// Check for database presence as well Maybe use a read replica here ?
|
||||
let redis_value = serde_json::to_string(&updated_intent)
|
||||
.into_report()
|
||||
.change_context(errors::StorageError::KVError)?;
|
||||
let updated_intent = self
|
||||
.redis_conn
|
||||
.serialize_and_set_hash_fields(&key, ("pi", &updated_intent))
|
||||
.set_hash_fields(&key, ("pi", &redis_value))
|
||||
.await
|
||||
.map(|_| updated_intent)
|
||||
.change_context(errors::StorageError::KVError)?;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use redis_interface::{errors::RedisError, RedisEntryId, SetNXReply};
|
||||
use redis_interface::{errors::RedisError, RedisEntryId, SetnxReply};
|
||||
use router_env::logger;
|
||||
|
||||
use super::{MockDb, Store};
|
||||
@ -70,7 +70,7 @@ impl QueueInterface for Store {
|
||||
let conn = self.redis_conn.clone();
|
||||
let is_lock_acquired = conn.set_key_if_not_exist(lock_key, lock_val).await;
|
||||
match is_lock_acquired {
|
||||
Ok(SetNXReply::KeySet) => match conn.set_expiry(lock_key, ttl).await {
|
||||
Ok(SetnxReply::KeySet) => match conn.set_expiry(lock_key, ttl).await {
|
||||
Ok(()) => true,
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
@ -80,7 +80,7 @@ impl QueueInterface for Store {
|
||||
false
|
||||
}
|
||||
},
|
||||
Ok(SetNXReply::KeyNotSet) => {
|
||||
Ok(SetnxReply::KeyNotSet) => {
|
||||
logger::error!(%tag, "Lock not acquired, previous fetch still in progress");
|
||||
false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user