feat(multitenancy): add tenant_id as a field for data pipeline and support individual database for clickhouse (#4867)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Arun Raj M <jarnura47@gmail.com>
Co-authored-by: Sampras Lopes <sampras.lopes@juspay.in>
This commit is contained in:
Jagan
2024-06-18 18:58:46 +05:30
committed by GitHub
parent d2092dcb0a
commit 776ddb8c1a
15 changed files with 55 additions and 68 deletions

View File

@ -129,6 +129,7 @@ pub struct Settings<S: SecretState> {
pub struct Multitenancy {
pub tenants: TenantConfig,
pub enabled: bool,
pub global_tenant: GlobalTenant,
}
impl Multitenancy {
@ -153,6 +154,7 @@ pub struct Tenant {
pub base_url: String,
pub schema: String,
pub redis_key_prefix: String,
pub clickhouse_database: String,
}
impl storage_impl::config::TenantConfig for Tenant {
@ -164,6 +166,12 @@ impl storage_impl::config::TenantConfig for Tenant {
}
}
impl storage_impl::config::ClickHouseConfig for Tenant {
fn get_clickhouse_database(&self) -> &str {
self.clickhouse_database.as_str()
}
}
#[derive(Debug, Deserialize, Clone, Default)]
pub struct GlobalTenant {
pub schema: String,

View File

@ -1,3 +1,4 @@
use common_utils::consts::TENANT_HEADER;
use futures::StreamExt;
use router_env::{
logger,
@ -140,10 +141,17 @@ where
// TODO: have a common source of truth for the list of top level fields
// /crates/router_env/src/logger/storage.rs also has a list of fields called PERSISTENT_KEYS
fn call(&self, req: actix_web::dev::ServiceRequest) -> Self::Future {
let tenant_id = req
.headers()
.get(TENANT_HEADER)
.and_then(|i| i.to_str().ok())
.map(|s| s.to_owned());
let response_fut = self.service.call(req);
Box::pin(
async move {
if let Some(tenant_id) = tenant_id {
router_env::tracing::Span::current().record("tenant_id", &tenant_id);
}
let response = response_fut.await;
router_env::tracing::Span::current().record("golden_log_line", true);
response

View File

@ -5,7 +5,6 @@ use actix_web::{web, Scope};
use api_models::routing::RoutingRetrieveQuery;
#[cfg(feature = "olap")]
use common_enums::TransactionType;
use common_utils::consts::{DEFAULT_TENANT, GLOBAL_TENANT};
#[cfg(feature = "email")]
use external_services::email::{ses::AwsSes, EmailService};
use external_services::file_storage::FileStorageInterface;
@ -257,19 +256,11 @@ impl AppState {
let cache_store = get_cache_store(&conf.clone(), shut_down_signal, testable)
.await
.expect("Failed to create store");
let global_tenant = if conf.multitenancy.enabled {
GLOBAL_TENANT
} else {
DEFAULT_TENANT
};
let global_store: Box<dyn GlobalStorageInterface> = Self::get_store_interface(
&storage_impl,
&event_handler,
&conf,
&settings::GlobalTenant {
schema: global_tenant.to_string(),
redis_key_prefix: String::default(),
},
&conf.multitenancy.global_tenant,
Arc::clone(&cache_store),
testable,
)
@ -288,9 +279,7 @@ impl AppState {
.get_storage_interface();
stores.insert(tenant_name.clone(), store);
#[cfg(feature = "olap")]
let pool =
AnalyticsProvider::from_conf(conf.analytics.get_inner(), tenant_name.as_str())
.await;
let pool = AnalyticsProvider::from_conf(conf.analytics.get_inner(), tenant).await;
#[cfg(feature = "olap")]
pools.insert(tenant_name.clone(), pool);
}

View File

@ -19,7 +19,7 @@ use api_models::enums::{CaptureMethod, PaymentMethodType};
pub use client::{proxy_bypass_urls, ApiClient, MockApiClient, ProxyClient};
pub use common_utils::request::{ContentType, Method, Request, RequestBuilder};
use common_utils::{
consts::X_HS_LATENCY,
consts::{DEFAULT_TENANT, TENANT_HEADER, X_HS_LATENCY},
errors::{ErrorSwitch, ReportSwitchExt},
request::RequestContent,
};
@ -783,10 +783,10 @@ where
.into_iter()
.collect();
let tenant_id = if !state.conf.multitenancy.enabled {
common_utils::consts::DEFAULT_TENANT.to_string()
DEFAULT_TENANT.to_string()
} else {
incoming_request_header
.get("x-tenant-id")
.get(TENANT_HEADER)
.and_then(|value| value.to_str().ok())
.ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch())
.map(|req_tenant_id| {