mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	fix: Implement persistent caching for config table retrieval (#2044)
Co-authored-by: Nitesh Balla <nitesh.balla@juspay.in> Co-authored-by: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Co-authored-by: BallaNitesh <126162378+BallaNitesh@users.noreply.github.com>
This commit is contained in:
		| @ -25,7 +25,7 @@ pub async fn set_config( | |||||||
|  |  | ||||||
| pub async fn read_config(store: &dyn StorageInterface, key: &str) -> RouterResponse<api::Config> { | pub async fn read_config(store: &dyn StorageInterface, key: &str) -> RouterResponse<api::Config> { | ||||||
|     let config = store |     let config = store | ||||||
|         .find_config_by_key_cached(key) |         .find_config_by_key(key) | ||||||
|         .await |         .await | ||||||
|         .to_not_found_response(errors::ApiErrorResponse::ConfigNotFound)?; |         .to_not_found_response(errors::ApiErrorResponse::ConfigNotFound)?; | ||||||
|     Ok(ApplicationResponse::Json(config.foreign_into())) |     Ok(ApplicationResponse::Json(config.foreign_into())) | ||||||
| @ -36,7 +36,7 @@ pub async fn update_config( | |||||||
|     config_update: &api::ConfigUpdate, |     config_update: &api::ConfigUpdate, | ||||||
| ) -> RouterResponse<api::Config> { | ) -> RouterResponse<api::Config> { | ||||||
|     let config = store |     let config = store | ||||||
|         .update_config_cached(&config_update.key, config_update.foreign_into()) |         .update_config_by_key(&config_update.key, config_update.foreign_into()) | ||||||
|         .await |         .await | ||||||
|         .to_not_found_response(errors::ApiErrorResponse::ConfigNotFound)?; |         .to_not_found_response(errors::ApiErrorResponse::ConfigNotFound)?; | ||||||
|     Ok(ApplicationResponse::Json(config.foreign_into())) |     Ok(ApplicationResponse::Json(config.foreign_into())) | ||||||
|  | |||||||
| @ -106,7 +106,7 @@ where | |||||||
|     let connector_api_version = if supported_connector.contains(&connector_enum) { |     let connector_api_version = if supported_connector.contains(&connector_enum) { | ||||||
|         state |         state | ||||||
|             .store |             .store | ||||||
|             .find_config_by_key_cached(&format!("connector_api_version_{connector_id}")) |             .find_config_by_key(&format!("connector_api_version_{connector_id}")) | ||||||
|             .await |             .await | ||||||
|             .map(|value| value.config) |             .map(|value| value.config) | ||||||
|             .ok() |             .ok() | ||||||
|  | |||||||
| @ -262,7 +262,7 @@ pub async fn construct_refund_router_data<'a, F>( | |||||||
|     let connector_api_version = if supported_connector.contains(&connector_enum) { |     let connector_api_version = if supported_connector.contains(&connector_enum) { | ||||||
|         state |         state | ||||||
|             .store |             .store | ||||||
|             .find_config_by_key_cached(&format!("connector_api_version_{connector_id}")) |             .find_config_by_key(&format!("connector_api_version_{connector_id}")) | ||||||
|             .await |             .await | ||||||
|             .map(|value| value.config) |             .map(|value| value.config) | ||||||
|             .ok() |             .ok() | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ pub async fn lookup_webhook_event( | |||||||
|         Ok(merchant_webhook_config) => merchant_webhook_config.contains(event), |         Ok(merchant_webhook_config) => merchant_webhook_config.contains(event), | ||||||
|         Err(..) => { |         Err(..) => { | ||||||
|             //if failed to fetch from redis. fetch from db and populate redis |             //if failed to fetch from redis. fetch from db and populate redis | ||||||
|             db.find_config_by_key_cached(&redis_key) |             db.find_config_by_key(&redis_key) | ||||||
|                 .await |                 .await | ||||||
|                 .map(|config| { |                 .map(|config| { | ||||||
|                     if let Ok(set) = |                     if let Ok(set) = | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ pub trait ConfigInterface { | |||||||
|         key: &str, |         key: &str, | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError>; |     ) -> CustomResult<storage::Config, errors::StorageError>; | ||||||
|  |  | ||||||
|     async fn find_config_by_key_cached( |     async fn find_config_by_key_from_db( | ||||||
|         &self, |         &self, | ||||||
|         key: &str, |         key: &str, | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError>; |     ) -> CustomResult<storage::Config, errors::StorageError>; | ||||||
| @ -36,12 +36,6 @@ pub trait ConfigInterface { | |||||||
|         config_update: storage::ConfigUpdate, |         config_update: storage::ConfigUpdate, | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError>; |     ) -> CustomResult<storage::Config, errors::StorageError>; | ||||||
|  |  | ||||||
|     async fn update_config_cached( |  | ||||||
|         &self, |  | ||||||
|         key: &str, |  | ||||||
|         config_update: storage::ConfigUpdate, |  | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError>; |  | ||||||
|  |  | ||||||
|     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError>; |     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError>; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -55,32 +49,8 @@ impl ConfigInterface for Store { | |||||||
|         config.insert(&conn).await.map_err(Into::into).into_report() |         config.insert(&conn).await.map_err(Into::into).into_report() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     //fetch directly from DB |  | ||||||
|     async fn find_config_by_key( |  | ||||||
|         &self, |  | ||||||
|         key: &str, |  | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |  | ||||||
|         let conn = connection::pg_connection_write(self).await?; |  | ||||||
|         storage::Config::find_by_key(&conn, key) |  | ||||||
|             .await |  | ||||||
|             .map_err(Into::into) |  | ||||||
|             .into_report() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async fn update_config_by_key( |  | ||||||
|         &self, |  | ||||||
|         key: &str, |  | ||||||
|         config_update: storage::ConfigUpdate, |  | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |  | ||||||
|         let conn = connection::pg_connection_write(self).await?; |  | ||||||
|         storage::Config::update_by_key(&conn, key, config_update) |  | ||||||
|             .await |  | ||||||
|             .map_err(Into::into) |  | ||||||
|             .into_report() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     //update in DB and remove in redis and cache |     //update in DB and remove in redis and cache | ||||||
|     async fn update_config_cached( |     async fn update_config_by_key( | ||||||
|         &self, |         &self, | ||||||
|         key: &str, |         key: &str, | ||||||
|         config_update: storage::ConfigUpdate, |         config_update: storage::ConfigUpdate, | ||||||
| @ -91,13 +61,29 @@ impl ConfigInterface for Store { | |||||||
|         .await |         .await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     //check in cache, then redis then finally DB, and on the way back populate redis and cache |     async fn find_config_by_key_from_db( | ||||||
|     async fn find_config_by_key_cached( |  | ||||||
|         &self, |         &self, | ||||||
|         key: &str, |         key: &str, | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |     ) -> CustomResult<storage::Config, errors::StorageError> { | ||||||
|         cache::get_or_populate_in_memory(self, key, || self.find_config_by_key(key), &CONFIG_CACHE) |         let conn = connection::pg_connection_write(self).await?; | ||||||
|  |         storage::Config::find_by_key(&conn, key) | ||||||
|             .await |             .await | ||||||
|  |             .map_err(Into::into) | ||||||
|  |             .into_report() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //check in cache, then redis then finally DB, and on the way back populate redis and cache | ||||||
|  |     async fn find_config_by_key( | ||||||
|  |         &self, | ||||||
|  |         key: &str, | ||||||
|  |     ) -> CustomResult<storage::Config, errors::StorageError> { | ||||||
|  |         cache::get_or_populate_in_memory( | ||||||
|  |             self, | ||||||
|  |             key, | ||||||
|  |             || self.find_config_by_key_from_db(key), | ||||||
|  |             &CONFIG_CACHE, | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError> { |     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError> { | ||||||
| @ -138,18 +124,6 @@ impl ConfigInterface for MockDb { | |||||||
|         Ok(config_new) |         Ok(config_new) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn find_config_by_key( |  | ||||||
|         &self, |  | ||||||
|         key: &str, |  | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |  | ||||||
|         let configs = self.configs.lock().await; |  | ||||||
|         let config = configs.iter().find(|c| c.key == key).cloned(); |  | ||||||
|  |  | ||||||
|         config.ok_or_else(|| { |  | ||||||
|             errors::StorageError::ValueNotFound("cannot find config".to_string()).into() |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async fn update_config_by_key( |     async fn update_config_by_key( | ||||||
|         &self, |         &self, | ||||||
|         key: &str, |         key: &str, | ||||||
| @ -174,30 +148,6 @@ impl ConfigInterface for MockDb { | |||||||
|  |  | ||||||
|         result |         result | ||||||
|     } |     } | ||||||
|     async fn update_config_cached( |  | ||||||
|         &self, |  | ||||||
|         key: &str, |  | ||||||
|         config_update: storage::ConfigUpdate, |  | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |  | ||||||
|         let result = self |  | ||||||
|             .configs |  | ||||||
|             .lock() |  | ||||||
|             .await |  | ||||||
|             .iter_mut() |  | ||||||
|             .find(|c| c.key == key) |  | ||||||
|             .ok_or_else(|| { |  | ||||||
|                 errors::StorageError::ValueNotFound("cannot find config to update".to_string()) |  | ||||||
|                     .into() |  | ||||||
|             }) |  | ||||||
|             .map(|c| { |  | ||||||
|                 let config_updated = |  | ||||||
|                     ConfigUpdateInternal::from(config_update).create_config(c.clone()); |  | ||||||
|                 *c = config_updated.clone(); |  | ||||||
|                 config_updated |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|         result |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError> { |     async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError> { | ||||||
|         let mut configs = self.configs.lock().await; |         let mut configs = self.configs.lock().await; | ||||||
| @ -216,7 +166,19 @@ impl ConfigInterface for MockDb { | |||||||
|         result |         result | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn find_config_by_key_cached( |     async fn find_config_by_key_from_db( | ||||||
|  |         &self, | ||||||
|  |         key: &str, | ||||||
|  |     ) -> CustomResult<storage::Config, errors::StorageError> { | ||||||
|  |         let configs = self.configs.lock().await; | ||||||
|  |         let config = configs.iter().find(|c| c.key == key).cloned(); | ||||||
|  |  | ||||||
|  |         config.ok_or_else(|| { | ||||||
|  |             errors::StorageError::ValueNotFound("cannot find config".to_string()).into() | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async fn find_config_by_key( | ||||||
|         &self, |         &self, | ||||||
|         key: &str, |         key: &str, | ||||||
|     ) -> CustomResult<storage::Config, errors::StorageError> { |     ) -> CustomResult<storage::Config, errors::StorageError> { | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ pub async fn get_sync_process_schedule_time( | |||||||
|         process_data::ConnectorPTMapping, |         process_data::ConnectorPTMapping, | ||||||
|         errors::StorageError, |         errors::StorageError, | ||||||
|     > = db |     > = db | ||||||
|         .find_config_by_key_cached(&format!("pt_mapping_{connector}")) |         .find_config_by_key(&format!("pt_mapping_{connector}")) | ||||||
|         .await |         .await | ||||||
|         .map(|value| value.config) |         .map(|value| value.config) | ||||||
|         .and_then(|config| { |         .and_then(|config| { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Kartikeya Hegde
					Kartikeya Hegde