feat: add per-connection configurable connect timeout
Add a `connect_timeout_secs` field to ConnectionConfig that allows users to configure the database connection timeout per connection (1-300s, default 5s). Previously all connections used a hardcoded 5-second timeout. - Add connect_timeout_secs field with serde default and clamp logic - Add parse_connect_timeout_with_fallback to honor URL params over config - Pass user-configured timeout to all drivers (MySQL, Postgres, Redis, MongoDB, ClickHouse, SQL Server, Elasticsearch) and TCP probe - Add UI input in connection dialog SSH tab - Add i18n keys for en/zh-CN/es
This commit is contained in:
1 parent
ed10edb5f7
commit
c03b57c179
19 files changed
+186
-94
No files matched your search
@@ -219,33 +219,40 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
||||
let probe_result = probe_connection_endpoint(&config, &host, port).await;
|
||||
let url = connection_url_for_endpoint(&config, &host, port);
|
||||
let target = redacted_connection_url_for_endpoint(&config, &host, port);
|
||||
let connect_timeout = std::time::Duration::from_secs(config.effective_connect_timeout_secs());
|
||||
log::info!("[test_connection] db_type={:?} target={}", config.db_type, target);
|
||||
let result = match probe_result {
|
||||
Err(e) => Err(e),
|
||||
Ok(()) => match config.db_type {
|
||||
DatabaseType::Mysql if config.needs_bare_mysql() => match db::mysql::connect_bare(&url).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
DatabaseType::Mysql if config.needs_bare_mysql() => {
|
||||
match db::mysql::connect_bare(&url, connect_timeout).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
DatabaseType::Mysql => match db::mysql::connect_with_ca_cert(&url, Some(&config.ca_cert_path)).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
DatabaseType::Mysql => {
|
||||
match db::mysql::connect_with_ca_cert(&url, Some(&config.ca_cert_path), connect_timeout).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
DatabaseType::Doris | DatabaseType::StarRocks => match db::mysql::connect_bare(&url).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
DatabaseType::Doris | DatabaseType::StarRocks => {
|
||||
match db::mysql::connect_bare(&url, connect_timeout).await {
|
||||
Ok(pool) => {
|
||||
let _ = pool.disconnect().await;
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
}
|
||||
DatabaseType::Postgres | DatabaseType::Redshift | DatabaseType::Gaussdb | DatabaseType::OpenGauss => {
|
||||
match db::postgres::connect(&url).await {
|
||||
match db::postgres::connect(&url, connect_timeout).await {
|
||||
Ok(pool) => {
|
||||
pool.close();
|
||||
Ok("Connection successful".to_string())
|
||||
@@ -264,7 +271,7 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
||||
} else if config.uses_redis_sentinel() {
|
||||
db::redis_driver::connect_sentinel(&config).await?
|
||||
} else {
|
||||
db::redis_driver::connect(&url).await?
|
||||
db::redis_driver::connect(&url, connect_timeout).await?
|
||||
};
|
||||
drop(con);
|
||||
Ok("Connection successful".to_string())
|
||||
@@ -279,8 +286,8 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
||||
}
|
||||
}
|
||||
DatabaseType::MongoDb => {
|
||||
let native_err = match db::mongo_driver::connect(&url).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(&client).await {
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(&client, connect_timeout).await {
|
||||
Ok(()) => return Ok("Connection successful".to_string()),
|
||||
Err(e) => e,
|
||||
},
|
||||
@@ -307,22 +314,35 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
||||
username,
|
||||
password,
|
||||
Some(&config.ca_cert_path),
|
||||
connect_timeout,
|
||||
)?;
|
||||
db::clickhouse_driver::test_connection(&client).await.map(|_| "Connection successful".to_string())
|
||||
}
|
||||
DatabaseType::SqlServer => {
|
||||
db::sqlserver::connect(&host, port, &config.username, &config.password, config.database.as_deref())
|
||||
db::clickhouse_driver::test_connection(&client, connect_timeout)
|
||||
.await
|
||||
.map(|_| "Connection successful".to_string())
|
||||
}
|
||||
DatabaseType::SqlServer => {
|
||||
db::sqlserver::connect(
|
||||
&host,
|
||||
port,
|
||||
&config.username,
|
||||
&config.password,
|
||||
config.database.as_deref(),
|
||||
connect_timeout,
|
||||
)
|
||||
.await
|
||||
.map(|_| "Connection successful".to_string())
|
||||
}
|
||||
DatabaseType::Elasticsearch => {
|
||||
let client = db::elasticsearch_driver::EsClient::new(
|
||||
&url,
|
||||
Some(&config.username),
|
||||
Some(&config.password),
|
||||
config.ssl,
|
||||
connect_timeout,
|
||||
);
|
||||
db::elasticsearch_driver::test_connection(&client).await.map(|_| "Connection successful".to_string())
|
||||
db::elasticsearch_driver::test_connection(&client, connect_timeout)
|
||||
.await
|
||||
.map(|_| "Connection successful".to_string())
|
||||
}
|
||||
db_type if database_capabilities::is_agent_type(&db_type) => {
|
||||
test_agent_connection(state.inner(), &config, &host, port).await
|
||||
@@ -362,20 +382,21 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
let (host, port) = state.connection_host_port(&id, &db_config).await?;
|
||||
probe_connection_endpoint(&db_config, &host, port).await?;
|
||||
let url = connection_url_for_endpoint(&db_config, &host, port);
|
||||
let connect_timeout = std::time::Duration::from_secs(db_config.effective_connect_timeout_secs());
|
||||
|
||||
let pool = match db_config.db_type {
|
||||
DatabaseType::Mysql if db_config.needs_bare_mysql() => {
|
||||
PoolKind::Mysql(db::mysql::connect_bare(&url).await?, MysqlMode::Bare)
|
||||
PoolKind::Mysql(db::mysql::connect_bare(&url, connect_timeout).await?, MysqlMode::Bare)
|
||||
}
|
||||
DatabaseType::Mysql => PoolKind::Mysql(
|
||||
db::mysql::connect_with_ca_cert(&url, Some(&db_config.ca_cert_path)).await?,
|
||||
db::mysql::connect_with_ca_cert(&url, Some(&db_config.ca_cert_path), connect_timeout).await?,
|
||||
MysqlMode::Normal,
|
||||
),
|
||||
DatabaseType::Doris | DatabaseType::StarRocks => {
|
||||
PoolKind::Mysql(db::mysql::connect_bare(&url).await?, MysqlMode::Bare)
|
||||
PoolKind::Mysql(db::mysql::connect_bare(&url, connect_timeout).await?, MysqlMode::Bare)
|
||||
}
|
||||
DatabaseType::Postgres | DatabaseType::Redshift | DatabaseType::Gaussdb | DatabaseType::OpenGauss => {
|
||||
PoolKind::Postgres(db::postgres::connect(&url).await?)
|
||||
PoolKind::Postgres(db::postgres::connect(&url, connect_timeout).await?)
|
||||
}
|
||||
DatabaseType::Sqlite => PoolKind::Sqlite(db::sqlite::connect_path(&expand_tilde(&db_config.host)).await?),
|
||||
DatabaseType::Redis => {
|
||||
@@ -389,7 +410,7 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
)))
|
||||
} else {
|
||||
PoolKind::Redis(db::redis_driver::RedisConnection::Direct(tokio::sync::Mutex::new(
|
||||
db::redis_driver::connect(&url).await?,
|
||||
db::redis_driver::connect(&url, connect_timeout).await?,
|
||||
)))
|
||||
};
|
||||
con
|
||||
@@ -405,8 +426,8 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
PoolKind::DuckDb(con)
|
||||
}
|
||||
DatabaseType::MongoDb => {
|
||||
let native_err = match db::mongo_driver::connect(&url).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(&client).await {
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(&client, connect_timeout).await {
|
||||
Ok(()) => {
|
||||
state.configs.write().await.insert(id.clone(), config);
|
||||
state.connections.write().await.insert(id.clone(), PoolKind::MongoDb(client));
|
||||
@@ -435,8 +456,9 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
username,
|
||||
password,
|
||||
Some(&db_config.ca_cert_path),
|
||||
connect_timeout,
|
||||
)?;
|
||||
db::clickhouse_driver::test_connection(&client).await?;
|
||||
db::clickhouse_driver::test_connection(&client, connect_timeout).await?;
|
||||
PoolKind::ClickHouse(client)
|
||||
}
|
||||
DatabaseType::SqlServer => {
|
||||
@@ -446,6 +468,7 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
&db_config.username,
|
||||
&db_config.password,
|
||||
db_config.database.as_deref(),
|
||||
connect_timeout,
|
||||
)
|
||||
.await?;
|
||||
PoolKind::SqlServer(std::sync::Arc::new(tokio::sync::Mutex::new(client)))
|
||||
@@ -456,8 +479,9 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
||||
Some(&db_config.username),
|
||||
Some(&db_config.password),
|
||||
db_config.ssl,
|
||||
connect_timeout,
|
||||
);
|
||||
db::elasticsearch_driver::test_connection(&client).await?;
|
||||
db::elasticsearch_driver::test_connection(&client, connect_timeout).await?;
|
||||
PoolKind::Elasticsearch(client)
|
||||
}
|
||||
db_type if database_capabilities::is_agent_type(&db_type) => {
|
||||
|
||||
Reference in new issue
Block a user