fix(oracle): auto-reconnect on closed connection and add debug logging

Detect closed Oracle connections in get_or_create_pool and
automatically reconnect instead of failing all subsequent operations.
Add debug/error logging to Oracle driver for easier troubleshooting.
This commit is contained in:
t8y2 2026-05-06 14:29:22 +08:00
parent e315c4ad36
commit 0d1b99e3ee
2 changed files with 36 additions and 7 deletions

View File

@ -72,9 +72,22 @@ impl AppState {
let conns = self.connections.lock().await;
if conns.contains_key(&pool_key) {
return Ok(pool_key);
if let Some(PoolKind::Oracle(client)) = conns.get(&pool_key) {
let conn = client.lock().await;
if conn.is_closed() {
drop(conn);
drop(conns);
log::info!("[oracle] connection closed, reconnecting...");
self.connections.lock().await.remove(&pool_key);
} else {
return Ok(pool_key);
}
} else {
return Ok(pool_key);
}
} else {
drop(conns);
}
drop(conns);
let configs = self.configs.lock().await;
let config = configs.get(connection_id).ok_or("Connection config not found")?.clone();

View File

@ -1,3 +1,4 @@
use log;
use oracle_rs::{Config, Connection};
use std::time::Instant;
@ -37,8 +38,11 @@ fn value_to_json(val: &oracle_rs::Value) -> serde_json::Value {
}
pub async fn list_databases(conn: &OracleClient) -> Result<Vec<DatabaseInfo>, String> {
let result =
conn.query("SELECT username FROM all_users ORDER BY username", &[]).await.map_err(|e| e.to_string())?;
log::debug!("[oracle] list_databases: querying all_users");
let result = conn.query("SELECT username FROM all_users ORDER BY username", &[]).await.map_err(|e| {
log::error!("[oracle] list_databases failed: {e}");
e.to_string()
})?;
Ok(result.rows.iter().map(|row| DatabaseInfo { name: row.get_string(0).unwrap_or("").to_string() }).collect())
}
@ -56,7 +60,11 @@ pub async fn list_tables(conn: &OracleClient, schema: &str) -> Result<Vec<TableI
ORDER BY 1",
s = schema.replace('\'', "''")
);
let result = conn.query(&sql, &[]).await.map_err(|e| e.to_string())?;
log::debug!("[oracle] list_tables: schema={schema}, sql={sql}");
let result = conn.query(&sql, &[]).await.map_err(|e| {
log::error!("[oracle] list_tables failed: {e}");
e.to_string()
})?;
Ok(result
.rows
.iter()
@ -68,6 +76,7 @@ pub async fn list_tables(conn: &OracleClient, schema: &str) -> Result<Vec<TableI
}
pub async fn get_columns(conn: &OracleClient, schema: &str, table: &str) -> Result<Vec<ColumnInfo>, String> {
log::debug!("[oracle] get_columns: schema={schema}, table={table}");
let s = schema.replace('\'', "''");
let t = table.replace('\'', "''");
@ -81,7 +90,10 @@ pub async fn get_columns(conn: &OracleClient, schema: &str, table: &str) -> Resu
&[],
)
.await
.map_err(|e| e.to_string())?;
.map_err(|e| {
log::error!("[oracle] get_columns pk query failed: {e}");
e.to_string()
})?;
let pk_names: std::collections::HashSet<String> =
pk_result.rows.iter().filter_map(|row| row.get_string(0).map(|s| s.to_string())).collect();
@ -229,6 +241,7 @@ pub async fn execute_query(conn: &OracleClient, sql: &str) -> Result<QueryResult
let start = Instant::now();
let sql = sql.trim().trim_end_matches(';');
let trimmed = sql.to_uppercase();
log::debug!("[oracle] execute_query: sql={}", &sql[..sql.len().min(200)]);
if trimmed.starts_with("SELECT")
|| trimmed.starts_with("WITH")
@ -236,7 +249,10 @@ pub async fn execute_query(conn: &OracleClient, sql: &str) -> Result<QueryResult
|| trimmed.starts_with("DESCRIBE")
|| trimmed.starts_with("EXPLAIN")
{
let result = conn.query(sql, &[]).await.map_err(|e| e.to_string())?;
let result = conn.query(sql, &[]).await.map_err(|e| {
log::error!("[oracle] execute_query SELECT failed: {e}");
e.to_string()
})?;
let columns: Vec<String> = result.columns.iter().map(|c| c.name.clone()).collect();
let rows: Vec<Vec<serde_json::Value>> = result
.rows