From 4dd2736b796520aa5f49920b62b182f3df83411a Mon Sep 17 00:00:00 2001 From: youxq Date: Thu, 12 Sep 2024 15:58:55 +0800 Subject: [PATCH 1/3] fix: timed out fetching a new connection from the connection pool.(prisma/prisma#25162) --- quaint/src/connector/postgres/native/mod.rs | 81 +++++++++++++------ quaint/src/pooled.rs | 7 +- quaint/src/pooled/manager.rs | 8 +- quaint/src/single.rs | 3 +- .../src/flavour/postgres/connection.rs | 5 +- 5 files changed, 70 insertions(+), 34 deletions(-) diff --git a/quaint/src/connector/postgres/native/mod.rs b/quaint/src/connector/postgres/native/mod.rs index 805ba13a602..f8f781de0f3 100644 --- a/quaint/src/connector/postgres/native/mod.rs +++ b/quaint/src/connector/postgres/native/mod.rs @@ -25,6 +25,7 @@ use column_type::PGColumnType; use futures::{future::FutureExt, lock::Mutex}; use lru_cache::LruCache; use native_tls::{Certificate, Identity, TlsConnector}; +use tokio::sync::OnceCell; use postgres_native_tls::MakeTlsConnector; use postgres_types::{Kind as PostgresKind, Type as PostgresType}; use std::hash::{DefaultHasher, Hash, Hasher}; @@ -228,27 +229,10 @@ impl PostgresUrl { impl PostgreSql { /// Create a new connection to the database. - pub async fn new(url: PostgresUrl) -> crate::Result { + pub async fn new(url: PostgresUrl, tls_manager: &MakeTlsConnectorManager) -> crate::Result { let config = url.to_config(); - let mut tls_builder = TlsConnector::builder(); - - { - let ssl_params = url.ssl_params(); - let auth = ssl_params.to_owned().into_auth().await?; - - if let Some(certificate) = auth.certificate.0 { - tls_builder.add_root_certificate(certificate); - } - - tls_builder.danger_accept_invalid_certs(auth.ssl_accept_mode == SslAcceptMode::AcceptInvalidCerts); - - if let Some(identity) = auth.identity.0 { - tls_builder.identity(identity); - } - } - - let tls = MakeTlsConnector::new(tls_builder.build()?); + let tls = tls_manager.get_connector().await?; let (client, conn) = timeout::connect(url.connect_timeout(), config.connect(tls)).await?; let is_cockroachdb = conn.parameter("crdb_version").is_some(); @@ -907,6 +891,45 @@ fn is_safe_identifier(ident: &str) -> bool { true } +pub struct MakeTlsConnectorManager { + url: PostgresUrl, + connector: OnceCell, +} + +impl MakeTlsConnectorManager { + pub fn new(url: PostgresUrl) -> Self { + MakeTlsConnectorManager { + url, + connector: OnceCell::new(), + } + } + + pub async fn get_connector(&self) -> crate::Result { + self.connector.get_or_try_init(|| async { + let mut tls_builder = TlsConnector::builder(); + + { + let ssl_params = self.url.ssl_params(); + let auth = ssl_params.to_owned().into_auth().await?; + + if let Some(certificate) = auth.certificate.0 { + tls_builder.add_root_certificate(certificate); + } + + tls_builder.danger_accept_invalid_certs(auth.ssl_accept_mode == SslAcceptMode::AcceptInvalidCerts); + + if let Some(identity) = auth.identity.0 { + tls_builder.identity(identity); + } + } + + let tls_connector = MakeTlsConnector::new(tls_builder.build()?); + + Ok(tls_connector) + }).await.map(Clone::clone) + } +} + #[cfg(test)] mod tests { use super::*; @@ -925,7 +948,9 @@ mod tests { let mut pg_url = PostgresUrl::new(url).unwrap(); pg_url.set_flavour(PostgresFlavour::Postgres); - let client = PostgreSql::new(pg_url).await.unwrap(); + let tls_manager = MakeTlsConnectorManager::new(pg_url.clone()); + + let client = PostgreSql::new(pg_url, &tls_manager).await.unwrap(); let result_set = client.query_raw("SHOW search_path", &[]).await.unwrap(); let row = result_set.first().unwrap(); @@ -977,7 +1002,9 @@ mod tests { let mut pg_url = PostgresUrl::new(url).unwrap(); pg_url.set_flavour(PostgresFlavour::Postgres); - let client = PostgreSql::new(pg_url).await.unwrap(); + let tls_manager = MakeTlsConnectorManager::new(pg_url.clone()); + + let client = PostgreSql::new(pg_url, &tls_manager).await.unwrap(); let result_set = client.query_raw("SHOW search_path", &[]).await.unwrap(); let row = result_set.first().unwrap(); @@ -1028,7 +1055,9 @@ mod tests { let mut pg_url = PostgresUrl::new(url).unwrap(); pg_url.set_flavour(PostgresFlavour::Cockroach); - let client = PostgreSql::new(pg_url).await.unwrap(); + let tls_manager = MakeTlsConnectorManager::new(pg_url.clone()); + + let client = PostgreSql::new(pg_url, &tls_manager).await.unwrap(); let result_set = client.query_raw("SHOW search_path", &[]).await.unwrap(); let row = result_set.first().unwrap(); @@ -1079,7 +1108,9 @@ mod tests { let mut pg_url = PostgresUrl::new(url).unwrap(); pg_url.set_flavour(PostgresFlavour::Unknown); - let client = PostgreSql::new(pg_url).await.unwrap(); + let tls_manager = MakeTlsConnectorManager::new(pg_url.clone()); + + let client = PostgreSql::new(pg_url, &tls_manager).await.unwrap(); let result_set = client.query_raw("SHOW search_path", &[]).await.unwrap(); let row = result_set.first().unwrap(); @@ -1130,7 +1161,9 @@ mod tests { let mut pg_url = PostgresUrl::new(url).unwrap(); pg_url.set_flavour(PostgresFlavour::Unknown); - let client = PostgreSql::new(pg_url).await.unwrap(); + let tls_manager = MakeTlsConnectorManager::new(pg_url.clone()); + + let client = PostgreSql::new(pg_url, &tls_manager).await.unwrap(); let result_set = client.query_raw("SHOW search_path", &[]).await.unwrap(); let row = result_set.first().unwrap(); diff --git a/quaint/src/pooled.rs b/quaint/src/pooled.rs index 381f0c82414..f12129019e8 100644 --- a/quaint/src/pooled.rs +++ b/quaint/src/pooled.rs @@ -156,7 +156,7 @@ pub use manager::*; use crate::error::NativeErrorKind; use crate::{ - connector::ConnectionInfo, + connector::{ConnectionInfo, MakeTlsConnectorManager}, error::{Error, ErrorKind}, }; use mobc::Pool; @@ -312,7 +312,7 @@ impl Builder { url.set_flavour(flavour); } - if let QuaintManager::Postgres { ref mut url } = self.manager { + if let QuaintManager::Postgres { ref mut url, tls_manager: _ } = self.manager { url.set_flavour(flavour); } } @@ -421,7 +421,8 @@ impl Quaint { let max_connection_lifetime = url.max_connection_lifetime(); let max_idle_connection_lifetime = url.max_idle_connection_lifetime(); - let manager = QuaintManager::Postgres { url }; + let tls_manager = MakeTlsConnectorManager::new(url.clone()); + let manager = QuaintManager::Postgres { url, tls_manager }; let mut builder = Builder::new(s, manager)?; if let Some(limit) = connection_limit { diff --git a/quaint/src/pooled/manager.rs b/quaint/src/pooled/manager.rs index 7533dffcfcc..560e087bf6d 100644 --- a/quaint/src/pooled/manager.rs +++ b/quaint/src/pooled/manager.rs @@ -3,7 +3,7 @@ use crate::connector::MssqlUrl; #[cfg(feature = "mysql-native")] use crate::connector::MysqlUrl; #[cfg(feature = "postgresql-native")] -use crate::connector::PostgresUrl; +use crate::connector::{PostgresUrl, MakeTlsConnectorManager}; use crate::{ ast, connector::{self, impl_default_TransactionCapable, IsolationLevel, Queryable, Transaction, TransactionCapable}, @@ -85,7 +85,7 @@ pub enum QuaintManager { Mysql { url: MysqlUrl }, #[cfg(feature = "postgresql")] - Postgres { url: PostgresUrl }, + Postgres { url: PostgresUrl, tls_manager: MakeTlsConnectorManager }, #[cfg(feature = "sqlite")] Sqlite { url: String, db_name: String }, @@ -117,9 +117,9 @@ impl Manager for QuaintManager { } #[cfg(feature = "postgresql-native")] - QuaintManager::Postgres { url } => { + QuaintManager::Postgres { url, tls_manager } => { use crate::connector::PostgreSql; - Ok(Box::new(PostgreSql::new(url.clone()).await?) as Self::Connection) + Ok(Box::new(PostgreSql::new(url.clone(), tls_manager).await?) as Self::Connection) } #[cfg(feature = "mssql-native")] diff --git a/quaint/src/single.rs b/quaint/src/single.rs index cbf460c4150..ae1cc320168 100644 --- a/quaint/src/single.rs +++ b/quaint/src/single.rs @@ -149,7 +149,8 @@ impl Quaint { #[cfg(feature = "postgresql-native")] s if s.starts_with("postgres") || s.starts_with("postgresql") => { let url = connector::PostgresUrl::new(url::Url::parse(s)?)?; - let psql = connector::PostgreSql::new(url).await?; + let tls_manager = connector::MakeTlsConnectorManager::new(url.clone()); + let psql = connector::PostgreSql::new(url, &tls_manager).await?; Arc::new(psql) as Arc } #[cfg(feature = "mssql-native")] diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs index 3ca9b673b0a..e350b4a8d17 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs @@ -4,7 +4,7 @@ use enumflags2::BitFlags; use indoc::indoc; use psl::PreviewFeature; use quaint::{ - connector::{self, tokio_postgres::error::ErrorPosition, PostgresUrl}, + connector::{self, tokio_postgres::error::ErrorPosition, MakeTlsConnectorManager, PostgresUrl}, prelude::{ConnectionInfo, NativeConnectionInfo, Queryable}, }; use schema_connector::{ConnectorError, ConnectorResult, Namespaces}; @@ -22,8 +22,9 @@ impl Connection { details: err.to_string(), }) })?; + let tls_manager = MakeTlsConnectorManager::new(url.clone()); - let quaint = connector::PostgreSql::new(url.clone()) + let quaint = connector::PostgreSql::new(url.clone(), &tls_manager) .await .map_err(quaint_err(&url))?; From da82b635076dd25d6bff856e37490c71514fa1d6 Mon Sep 17 00:00:00 2001 From: youxq Date: Sun, 29 Sep 2024 11:13:23 +0800 Subject: [PATCH 2/3] fix(lint): use cloned method and fix rustfmt warning --- quaint/src/connector/postgres/native/mod.rs | 35 +++++++++++---------- quaint/src/pooled.rs | 6 +++- quaint/src/pooled/manager.rs | 7 +++-- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/quaint/src/connector/postgres/native/mod.rs b/quaint/src/connector/postgres/native/mod.rs index f8f781de0f3..386e4cfd0d6 100644 --- a/quaint/src/connector/postgres/native/mod.rs +++ b/quaint/src/connector/postgres/native/mod.rs @@ -25,7 +25,6 @@ use column_type::PGColumnType; use futures::{future::FutureExt, lock::Mutex}; use lru_cache::LruCache; use native_tls::{Certificate, Identity, TlsConnector}; -use tokio::sync::OnceCell; use postgres_native_tls::MakeTlsConnector; use postgres_types::{Kind as PostgresKind, Type as PostgresType}; use std::hash::{DefaultHasher, Hash, Hasher}; @@ -37,6 +36,7 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, time::Duration, }; +use tokio::sync::OnceCell; use tokio_postgres::{config::ChannelBinding, Client, Config, Statement}; /// The underlying postgres driver. Only available with the `expose-drivers` @@ -905,28 +905,31 @@ impl MakeTlsConnectorManager { } pub async fn get_connector(&self) -> crate::Result { - self.connector.get_or_try_init(|| async { - let mut tls_builder = TlsConnector::builder(); + self.connector + .get_or_try_init(|| async { + let mut tls_builder = TlsConnector::builder(); - { - let ssl_params = self.url.ssl_params(); - let auth = ssl_params.to_owned().into_auth().await?; + { + let ssl_params = self.url.ssl_params(); + let auth = ssl_params.to_owned().into_auth().await?; - if let Some(certificate) = auth.certificate.0 { - tls_builder.add_root_certificate(certificate); - } + if let Some(certificate) = auth.certificate.0 { + tls_builder.add_root_certificate(certificate); + } - tls_builder.danger_accept_invalid_certs(auth.ssl_accept_mode == SslAcceptMode::AcceptInvalidCerts); + tls_builder.danger_accept_invalid_certs(auth.ssl_accept_mode == SslAcceptMode::AcceptInvalidCerts); - if let Some(identity) = auth.identity.0 { - tls_builder.identity(identity); + if let Some(identity) = auth.identity.0 { + tls_builder.identity(identity); + } } - } - let tls_connector = MakeTlsConnector::new(tls_builder.build()?); + let tls_connector = MakeTlsConnector::new(tls_builder.build()?); - Ok(tls_connector) - }).await.map(Clone::clone) + Ok(tls_connector) + }) + .await + .cloned() } } diff --git a/quaint/src/pooled.rs b/quaint/src/pooled.rs index f12129019e8..382da16820a 100644 --- a/quaint/src/pooled.rs +++ b/quaint/src/pooled.rs @@ -312,7 +312,11 @@ impl Builder { url.set_flavour(flavour); } - if let QuaintManager::Postgres { ref mut url, tls_manager: _ } = self.manager { + if let QuaintManager::Postgres { + ref mut url, + tls_manager: _, + } = self.manager + { url.set_flavour(flavour); } } diff --git a/quaint/src/pooled/manager.rs b/quaint/src/pooled/manager.rs index 560e087bf6d..0024f69dbf5 100644 --- a/quaint/src/pooled/manager.rs +++ b/quaint/src/pooled/manager.rs @@ -3,7 +3,7 @@ use crate::connector::MssqlUrl; #[cfg(feature = "mysql-native")] use crate::connector::MysqlUrl; #[cfg(feature = "postgresql-native")] -use crate::connector::{PostgresUrl, MakeTlsConnectorManager}; +use crate::connector::{MakeTlsConnectorManager, PostgresUrl}; use crate::{ ast, connector::{self, impl_default_TransactionCapable, IsolationLevel, Queryable, Transaction, TransactionCapable}, @@ -85,7 +85,10 @@ pub enum QuaintManager { Mysql { url: MysqlUrl }, #[cfg(feature = "postgresql")] - Postgres { url: PostgresUrl, tls_manager: MakeTlsConnectorManager }, + Postgres { + url: PostgresUrl, + tls_manager: MakeTlsConnectorManager, + }, #[cfg(feature = "sqlite")] Sqlite { url: String, db_name: String }, From 122f6cb1bd42131e7e99d6c1149ea4e077244d39 Mon Sep 17 00:00:00 2001 From: youxq Date: Mon, 7 Oct 2024 16:49:43 +0800 Subject: [PATCH 3/3] fix(ci): resolve React Native build issue --- quaint/src/pooled.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quaint/src/pooled.rs b/quaint/src/pooled.rs index 382da16820a..5222efee6bc 100644 --- a/quaint/src/pooled.rs +++ b/quaint/src/pooled.rs @@ -156,7 +156,7 @@ pub use manager::*; use crate::error::NativeErrorKind; use crate::{ - connector::{ConnectionInfo, MakeTlsConnectorManager}, + connector::ConnectionInfo, error::{Error, ErrorKind}, }; use mobc::Pool; @@ -425,7 +425,7 @@ impl Quaint { let max_connection_lifetime = url.max_connection_lifetime(); let max_idle_connection_lifetime = url.max_idle_connection_lifetime(); - let tls_manager = MakeTlsConnectorManager::new(url.clone()); + let tls_manager = crate::connector::MakeTlsConnectorManager::new(url.clone()); let manager = QuaintManager::Postgres { url, tls_manager }; let mut builder = Builder::new(s, manager)?;