Skip to content

Commit 4d0c893

Browse files
refactor(conditional_configs): refactor conditional_configs to use Moka Cache instead of Static Cache (#4814)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 2119de9 commit 4d0c893

File tree

13 files changed

+179
-170
lines changed

13 files changed

+179
-170
lines changed

crates/euclid/src/backend/vir_interpreter.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
pub mod types;
22

3+
use std::fmt::Debug;
4+
5+
use serde::{Deserialize, Serialize};
6+
37
use crate::{
48
backend::{self, inputs, EuclidBackend},
59
frontend::{
@@ -9,6 +13,7 @@ use crate::{
913
},
1014
};
1115

16+
#[derive(Serialize, Deserialize, Debug, Clone)]
1217
pub struct VirInterpreterBackend<O> {
1318
program: vir::ValuedProgram<O>,
1419
}

crates/euclid/src/frontend/vir.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
//! Valued Intermediate Representation
2+
use serde::{Deserialize, Serialize};
3+
24
use crate::types::{EuclidValue, Metadata};
35

4-
#[derive(Debug, Clone)]
6+
#[derive(Debug, Clone, Serialize, Deserialize)]
57
pub enum ValuedComparisonLogic {
68
NegativeConjunction,
79
PositiveDisjunction,
810
}
911

10-
#[derive(Clone, Debug)]
12+
#[derive(Clone, Debug, Serialize, Deserialize)]
1113
pub struct ValuedComparison {
1214
pub values: Vec<EuclidValue>,
1315
pub logic: ValuedComparisonLogic,
@@ -16,20 +18,20 @@ pub struct ValuedComparison {
1618

1719
pub type ValuedIfCondition = Vec<ValuedComparison>;
1820

19-
#[derive(Clone, Debug)]
21+
#[derive(Clone, Debug, Serialize, Deserialize)]
2022
pub struct ValuedIfStatement {
2123
pub condition: ValuedIfCondition,
2224
pub nested: Option<Vec<ValuedIfStatement>>,
2325
}
2426

25-
#[derive(Clone, Debug)]
27+
#[derive(Clone, Debug, Serialize, Deserialize)]
2628
pub struct ValuedRule<O> {
2729
pub name: String,
2830
pub connector_selection: O,
2931
pub statements: Vec<ValuedIfStatement>,
3032
}
3133

32-
#[derive(Clone, Debug)]
34+
#[derive(Clone, Debug, Serialize, Deserialize)]
3335
pub struct ValuedProgram<O> {
3436
pub default_selection: O,
3537
pub rules: Vec<ValuedRule<O>>,

crates/euclid/src/types.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub mod transformers;
22

33
use euclid_macros::EnumNums;
4-
use serde::Serialize;
4+
use serde::{Deserialize, Serialize};
55
use strum::VariantNames;
66

77
use crate::{
@@ -143,7 +143,7 @@ impl EuclidKey {
143143

144144
enums::collect_variants!(EuclidKey);
145145

146-
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize)]
146+
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
147147
#[serde(rename_all = "snake_case")]
148148
pub enum NumValueRefinement {
149149
NotEqual,
@@ -178,18 +178,18 @@ impl From<NumValueRefinement> for ast::ComparisonType {
178178
}
179179
}
180180

181-
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize)]
181+
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
182182
pub struct StrValue {
183183
pub value: String,
184184
}
185185

186-
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize)]
186+
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
187187
pub struct MetadataValue {
188188
pub key: String,
189189
pub value: String,
190190
}
191191

192-
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize)]
192+
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
193193
pub struct NumValue {
194194
pub number: i64,
195195
pub refinement: Option<NumValueRefinement>,
@@ -234,7 +234,7 @@ impl NumValue {
234234
}
235235
}
236236

237-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
237+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
238238
pub enum EuclidValue {
239239
PaymentMethod(enums::PaymentMethod),
240240
CardBin(StrValue),

crates/router/src/core/conditional_config.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use common_utils::ext_traits::{Encode, StringExt, ValueExt};
66
use diesel_models::configs;
77
use error_stack::ResultExt;
88
use euclid::frontend::ast;
9+
use storage_impl::redis::cache;
910

1011
use super::routing::helpers::{
1112
get_payment_config_routing_id, update_merchant_active_algorithm_ref,
@@ -99,8 +100,9 @@ pub async fn upsert_conditional_config(
99100
.change_context(errors::ApiErrorResponse::InternalServerError)
100101
.attach_printable("Error serializing the config")?;
101102

102-
algo_id.update_conditional_config_id(key);
103-
update_merchant_active_algorithm_ref(db, &key_store, algo_id)
103+
algo_id.update_conditional_config_id(key.clone());
104+
let config_key = cache::CacheKind::DecisionManager(key.into());
105+
update_merchant_active_algorithm_ref(db, &key_store, config_key, algo_id)
104106
.await
105107
.change_context(errors::ApiErrorResponse::InternalServerError)
106108
.attach_printable("Failed to update routing algorithm ref")?;
@@ -134,8 +136,9 @@ pub async fn upsert_conditional_config(
134136
.change_context(errors::ApiErrorResponse::InternalServerError)
135137
.attach_printable("Error fetching the config")?;
136138

137-
algo_id.update_conditional_config_id(key);
138-
update_merchant_active_algorithm_ref(db, &key_store, algo_id)
139+
algo_id.update_conditional_config_id(key.clone());
140+
let config_key = cache::CacheKind::DecisionManager(key.into());
141+
update_merchant_active_algorithm_ref(db, &key_store, config_key, algo_id)
139142
.await
140143
.change_context(errors::ApiErrorResponse::InternalServerError)
141144
.attach_printable("Failed to update routing algorithm ref")?;
@@ -164,7 +167,8 @@ pub async fn delete_conditional_config(
164167
.attach_printable("Could not decode the conditional_config algorithm")?
165168
.unwrap_or_default();
166169
algo_id.config_algo_id = None;
167-
update_merchant_active_algorithm_ref(db, &key_store, algo_id)
170+
let config_key = cache::CacheKind::DecisionManager(key.clone().into());
171+
update_merchant_active_algorithm_ref(db, &key_store, config_key, algo_id)
168172
.await
169173
.change_context(errors::ApiErrorResponse::InternalServerError)
170174
.attach_printable("Failed to update deleted algorithm ref")?;

crates/router/src/core/payment_methods/surcharge_decision_configs.rs

Lines changed: 35 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
use std::sync::Arc;
2-
31
use api_models::{
42
payment_methods::SurchargeDetailsResponse,
53
payments, routing,
64
surcharge_decision_configs::{self, SurchargeDecisionConfigs, SurchargeDecisionManagerRecord},
75
};
8-
use common_utils::{ext_traits::StringExt, static_cache::StaticCache, types as common_utils_types};
6+
use common_utils::{ext_traits::StringExt, types as common_utils_types};
97
use error_stack::{self, ResultExt};
108
use euclid::{
119
backend,
1210
backend::{inputs as dsl_inputs, EuclidBackend},
1311
};
1412
use router_env::{instrument, tracing};
13+
use serde::{Deserialize, Serialize};
14+
use storage_impl::redis::cache::{self, SURCHARGE_CACHE};
1515

1616
use crate::{
1717
core::{
18-
errors::ConditionalConfigError as ConfigError,
18+
errors::{self, ConditionalConfigError as ConfigError},
1919
payments::{
2020
conditional_configs::ConditionalConfigResult, routing::make_dsl_input_for_surcharge,
2121
types, PaymentData,
@@ -29,9 +29,8 @@ use crate::{
2929
SessionState,
3030
};
3131

32-
static CONF_CACHE: StaticCache<VirInterpreterBackendCacheWrapper> = StaticCache::new();
33-
34-
struct VirInterpreterBackendCacheWrapper {
32+
#[derive(Debug, Serialize, Deserialize, Clone)]
33+
pub struct VirInterpreterBackendCacheWrapper {
3534
cached_algorithm: backend::VirInterpreterBackend<SurchargeDecisionConfigs>,
3635
merchant_surcharge_configs: surcharge_decision_configs::MerchantSurchargeConfigs,
3736
}
@@ -53,7 +52,7 @@ impl TryFrom<SurchargeDecisionManagerRecord> for VirInterpreterBackendCacheWrapp
5352

5453
enum SurchargeSource {
5554
/// Surcharge will be generated through the surcharge rules
56-
Generate(Arc<VirInterpreterBackendCacheWrapper>),
55+
Generate(VirInterpreterBackendCacheWrapper),
5756
/// Surcharge is predefined by the merchant through payment create request
5857
Predetermined(payments::RequestSurchargeDetails),
5958
}
@@ -116,19 +115,13 @@ pub async fn perform_surcharge_decision_management_for_payment_method_list(
116115
surcharge_decision_configs::MerchantSurchargeConfigs::default(),
117116
),
118117
(None, Some(algorithm_id)) => {
119-
let key = ensure_algorithm_cached(
118+
let cached_algo = ensure_algorithm_cached(
120119
&*state.store,
121120
&payment_attempt.merchant_id,
122-
algorithm_ref.timestamp,
123121
algorithm_id.as_str(),
124122
)
125123
.await?;
126-
let cached_algo = CONF_CACHE
127-
.retrieve(&key)
128-
.change_context(ConfigError::CacheMiss)
129-
.attach_printable(
130-
"Unable to retrieve cached routing algorithm even after refresh",
131-
)?;
124+
132125
let merchant_surcharge_config = cached_algo.merchant_surcharge_configs.clone();
133126
(
134127
SurchargeSource::Generate(cached_algo),
@@ -233,19 +226,13 @@ where
233226
SurchargeSource::Predetermined(request_surcharge_details)
234227
}
235228
(None, Some(algorithm_id)) => {
236-
let key = ensure_algorithm_cached(
229+
let cached_algo = ensure_algorithm_cached(
237230
&*state.store,
238231
&payment_data.payment_attempt.merchant_id,
239-
algorithm_ref.timestamp,
240232
algorithm_id.as_str(),
241233
)
242234
.await?;
243-
let cached_algo = CONF_CACHE
244-
.retrieve(&key)
245-
.change_context(ConfigError::CacheMiss)
246-
.attach_printable(
247-
"Unable to retrieve cached routing algorithm even after refresh",
248-
)?;
235+
249236
SurchargeSource::Generate(cached_algo)
250237
}
251238
(None, None) => return Ok(surcharge_metadata),
@@ -291,19 +278,13 @@ pub async fn perform_surcharge_decision_management_for_saved_cards(
291278
SurchargeSource::Predetermined(request_surcharge_details)
292279
}
293280
(None, Some(algorithm_id)) => {
294-
let key = ensure_algorithm_cached(
281+
let cached_algo = ensure_algorithm_cached(
295282
&*state.store,
296283
&payment_attempt.merchant_id,
297-
algorithm_ref.timestamp,
298284
algorithm_id.as_str(),
299285
)
300286
.await?;
301-
let cached_algo = CONF_CACHE
302-
.retrieve(&key)
303-
.change_context(ConfigError::CacheMiss)
304-
.attach_printable(
305-
"Unable to retrieve cached routing algorithm even after refresh",
306-
)?;
287+
307288
SurchargeSource::Generate(cached_algo)
308289
}
309290
(None, None) => return Ok(surcharge_metadata),
@@ -388,48 +369,31 @@ fn get_surcharge_details_from_surcharge_output(
388369
pub async fn ensure_algorithm_cached(
389370
store: &dyn StorageInterface,
390371
merchant_id: &str,
391-
timestamp: i64,
392372
algorithm_id: &str,
393-
) -> ConditionalConfigResult<String> {
373+
) -> ConditionalConfigResult<VirInterpreterBackendCacheWrapper> {
394374
let key = format!("surcharge_dsl_{merchant_id}");
395-
let present = CONF_CACHE
396-
.present(&key)
397-
.change_context(ConfigError::DslCachePoisoned)
398-
.attach_printable("Error checking presence of DSL")?;
399-
let expired = CONF_CACHE
400-
.expired(&key, timestamp)
401-
.change_context(ConfigError::DslCachePoisoned)
402-
.attach_printable("Error checking presence of DSL")?;
403375

404-
if !present || expired {
405-
refresh_surcharge_algorithm_cache(store, key.clone(), algorithm_id, timestamp).await?
406-
}
407-
Ok(key)
408-
}
409-
410-
#[instrument(skip_all)]
411-
pub async fn refresh_surcharge_algorithm_cache(
412-
store: &dyn StorageInterface,
413-
key: String,
414-
algorithm_id: &str,
415-
timestamp: i64,
416-
) -> ConditionalConfigResult<()> {
417-
let config = store
418-
.find_config_by_key(algorithm_id)
419-
.await
420-
.change_context(ConfigError::DslMissingInDb)
421-
.attach_printable("Error parsing DSL from config")?;
422-
let record: SurchargeDecisionManagerRecord = config
423-
.config
424-
.parse_struct("Program")
425-
.change_context(ConfigError::DslParsingError)
426-
.attach_printable("Error parsing routing algorithm from configs")?;
427-
let value_to_cache = VirInterpreterBackendCacheWrapper::try_from(record)?;
428-
CONF_CACHE
429-
.save(key, value_to_cache, timestamp)
430-
.change_context(ConfigError::DslCachePoisoned)
431-
.attach_printable("Error saving DSL to cache")?;
432-
Ok(())
376+
let value_to_cache = || async {
377+
let config: diesel_models::Config = store.find_config_by_key(algorithm_id).await?;
378+
let record: SurchargeDecisionManagerRecord = config
379+
.config
380+
.parse_struct("Program")
381+
.change_context(errors::StorageError::DeserializationFailed)
382+
.attach_printable("Error parsing routing algorithm from configs")?;
383+
VirInterpreterBackendCacheWrapper::try_from(record)
384+
.change_context(errors::StorageError::ValueNotFound("Program".to_string()))
385+
.attach_printable("Error initializing DSL interpreter backend")
386+
};
387+
let interpreter = cache::get_or_populate_in_memory(
388+
store.get_cache_store().as_ref(),
389+
&key,
390+
value_to_cache,
391+
&SURCHARGE_CACHE,
392+
)
393+
.await
394+
.change_context(ConfigError::CacheMiss)
395+
.attach_printable("Unable to retrieve cached routing algorithm even after refresh")?;
396+
Ok(interpreter)
433397
}
434398

435399
pub fn execute_dsl_and_get_conditional_config(

0 commit comments

Comments
 (0)