From f079ade73180caf708f960b6a3901b7a4bf0db83 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Tue, 23 Dec 2025 00:05:37 +0800 Subject: [PATCH] fix(proxy): handle missing health records and clear health on proxy stop - Return default healthy state when provider health record not found - Add clear_provider_health_for_app to clear health for specific app - Clear app health records when stopping proxy takeover --- src-tauri/src/database/dao/proxy.rs | 73 ++++++++++++++++++++--------- src-tauri/src/services/proxy.rs | 8 +++- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src-tauri/src/database/dao/proxy.rs b/src-tauri/src/database/dao/proxy.rs index 9017ebe60..e2573df7d 100644 --- a/src-tauri/src/database/dao/proxy.rs +++ b/src-tauri/src/database/dao/proxy.rs @@ -102,28 +102,45 @@ impl Database { provider_id: &str, app_type: &str, ) -> Result { - let conn = lock_conn!(self.conn); + let result = { + let conn = lock_conn!(self.conn); - conn.query_row( - "SELECT provider_id, app_type, is_healthy, consecutive_failures, - last_success_at, last_failure_at, last_error, updated_at - FROM provider_health - WHERE provider_id = ?1 AND app_type = ?2", - rusqlite::params![provider_id, app_type], - |row| { - Ok(ProviderHealth { - provider_id: row.get(0)?, - app_type: row.get(1)?, - is_healthy: row.get::<_, i64>(2)? != 0, - consecutive_failures: row.get::<_, i64>(3)? as u32, - last_success_at: row.get(4)?, - last_failure_at: row.get(5)?, - last_error: row.get(6)?, - updated_at: row.get(7)?, - }) - }, - ) - .map_err(|e| AppError::Database(e.to_string())) + conn.query_row( + "SELECT provider_id, app_type, is_healthy, consecutive_failures, + last_success_at, last_failure_at, last_error, updated_at + FROM provider_health + WHERE provider_id = ?1 AND app_type = ?2", + rusqlite::params![provider_id, app_type], + |row| { + Ok(ProviderHealth { + provider_id: row.get(0)?, + app_type: row.get(1)?, + is_healthy: row.get::<_, i64>(2)? != 0, + consecutive_failures: row.get::<_, i64>(3)? as u32, + last_success_at: row.get(4)?, + last_failure_at: row.get(5)?, + last_error: row.get(6)?, + updated_at: row.get(7)?, + }) + }, + ) + }; + + match result { + Ok(health) => Ok(health), + // 缺少记录时视为健康(关闭后清空状态,再次打开时默认正常) + Err(rusqlite::Error::QueryReturnedNoRows) => Ok(ProviderHealth { + provider_id: provider_id.to_string(), + app_type: app_type.to_string(), + is_healthy: true, + consecutive_failures: 0, + last_success_at: None, + last_failure_at: None, + last_error: None, + updated_at: chrono::Utc::now().to_rfc3339(), + }), + Err(e) => Err(AppError::Database(e.to_string())), + } } /// 更新Provider健康状态 @@ -228,6 +245,20 @@ impl Database { Ok(()) } + /// 清空指定应用的健康状态(关闭单个代理时使用) + pub async fn clear_provider_health_for_app(&self, app_type: &str) -> Result<(), AppError> { + let conn = lock_conn!(self.conn); + + conn.execute( + "DELETE FROM provider_health WHERE app_type = ?1", + [app_type], + ) + .map_err(|e| AppError::Database(e.to_string()))?; + + log::debug!("Cleared provider health records for app {app_type}"); + Ok(()) + } + /// 清空所有Provider健康状态(代理停止时调用) pub async fn clear_all_provider_health(&self) -> Result<(), AppError> { let conn = lock_conn!(self.conn); diff --git a/src-tauri/src/services/proxy.rs b/src-tauri/src/services/proxy.rs index 34dd29906..03570eb05 100644 --- a/src-tauri/src/services/proxy.rs +++ b/src-tauri/src/services/proxy.rs @@ -258,7 +258,13 @@ impl ProxyService { .set_proxy_takeover_enabled(app_type_str, false) .map_err(|e| format!("清除 {app_type_str} 接管状态失败: {e}"))?; - // 4) 若无其它接管,更新旧标志,并停止代理服务 + // 4) 清除该应用的健康状态(关闭代理时重置队列状态) + self.db + .clear_provider_health_for_app(app_type_str) + .await + .map_err(|e| format!("清除 {app_type_str} 健康状态失败: {e}"))?; + + // 5) 若无其它接管,更新旧标志,并停止代理服务 let has_any_backup = self .db .has_any_live_backup()