From 73b9a71c8402b96c47bc3c1e5dc4553fe086fe76 Mon Sep 17 00:00:00 2001 From: wonfen Date: Sat, 3 May 2025 09:38:25 +0800 Subject: [PATCH] feat: add retry mechanism to optimize network requests, improve async message handling and timeout for scheduled tasks --- src-tauri/src/config/prfitem.rs | 2 +- src-tauri/src/core/handle.rs | 32 ++++++++++++----- src-tauri/src/core/timer.rs | 61 +++++++++++++++++---------------- src-tauri/src/utils/network.rs | 46 +++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 39 deletions(-) diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index 62ed8ab7..f0e6a155 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -265,7 +265,7 @@ impl PrfItem { // 使用网络管理器发送请求 let resp = NetworkManager::global() - .get( + .get_with_retry( url, proxy_type, Some(timeout), diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index 6140c1c3..67dd9d3d 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -108,14 +108,29 @@ impl Handle { return; } - // 已经完成启动,直接发送消息 - if let Some(window) = handle.get_window() { - logging_error!( - Type::Frontend, - true, - window.emit("verge://notice-message", (status_str, msg_str)) - ); - } + // 使用AsyncHandler发送消息,防止阻塞 + let status_clone = status_str.clone(); + let msg_clone = msg_str.clone(); + + crate::process::AsyncHandler::spawn(move || async move { + let handle_clone = Self::global(); + if let Some(window) = handle_clone.get_window() { + match tokio::time::timeout(tokio::time::Duration::from_millis(500), async { + window.emit("verge://notice-message", (status_clone, msg_clone)) + }) + .await + { + Ok(result) => { + if let Err(e) = result { + logging!(warn, Type::Frontend, true, "发送通知消息失败: {}", e); + } + } + Err(_) => { + logging!(warn, Type::Frontend, true, "发送通知消息超时"); + } + } + } + }); } /// 标记启动已完成,并发送所有启动阶段累积的错误消息 @@ -158,7 +173,6 @@ impl Handle { for error in errors_clone { let _ = window_clone.emit("verge://notice-message", (error.status, error.message)); - // 每条消息之间间隔500ms,避免消息堆积 tokio::time::sleep(Duration::from_millis(500)).await; } }); diff --git a/src-tauri/src/core/timer.rs b/src-tauri/src/core/timer.rs index 092a1fd4..7950ee5c 100644 --- a/src-tauri/src/core/timer.rs +++ b/src-tauri/src/core/timer.rs @@ -385,7 +385,6 @@ impl Timer { } }; - // 修复类型比较,使用字符串值比较而不是引用比较 let profile = match items .iter() .find(|item| item.uid.as_ref().map(|u| u.as_str()) == Some(uid)) @@ -424,7 +423,6 @@ impl Timer { /// Emit update events for frontend notification fn emit_update_event(_uid: &str, _is_start: bool) { - // 当feature="verge-dev"或"default"时才启用此功能 #[cfg(any(feature = "verge-dev", feature = "default"))] { use serde_json::json; @@ -443,39 +441,44 @@ impl Timer { } /// Async task with better error handling and logging + async fn async_task(uid: String) { let task_start = std::time::Instant::now(); logging!(info, Type::Timer, "Running timer task for profile: {}", uid); - // Emit start event - Self::emit_update_event(&uid, true); + match tokio::time::timeout(std::time::Duration::from_secs(40), async { + Self::emit_update_event(&uid, true); - // 检查是否是当前激活的配置文件 - let is_current = Config::profiles().latest().current.as_ref() == Some(&uid); - logging!( - info, - Type::Timer, - "配置 {} 是否为当前激活配置: {}", - uid, - is_current - ); + let is_current = Config::profiles().latest().current.as_ref() == Some(&uid); + logging!( + info, + Type::Timer, + "配置 {} 是否为当前激活配置: {}", + uid, + is_current + ); - // Update profile - 由update_profile函数自动处理是否需要刷新UI - let profile_result = feat::update_profile(uid.clone(), None, Some(is_current)).await; - - match profile_result { - Ok(_) => { - let duration = task_start.elapsed().as_millis(); - logging!( - info, - Type::Timer, - "Timer task completed successfully for uid: {} (took {}ms)", - uid, - duration - ); - } - Err(e) => { - logging_error!(Type::Timer, "Failed to update profile uid {}: {}", uid, e); + feat::update_profile(uid.clone(), None, Some(is_current)).await + }) + .await + { + Ok(result) => match result { + Ok(_) => { + let duration = task_start.elapsed().as_millis(); + logging!( + info, + Type::Timer, + "Timer task completed successfully for uid: {} (took {}ms)", + uid, + duration + ); + } + Err(e) => { + logging_error!(Type::Timer, "Failed to update profile uid {}: {}", uid, e); + } + }, + Err(_) => { + logging_error!(Type::Timer, false, "Timer task timed out for uid: {}", uid); } } diff --git a/src-tauri/src/utils/network.rs b/src-tauri/src/utils/network.rs index f65749a4..f0aba8fc 100644 --- a/src-tauri/src/utils/network.rs +++ b/src-tauri/src/utils/network.rs @@ -260,6 +260,52 @@ impl NetworkManager { .await .context("Failed to send HTTP request") } + pub async fn get_with_retry( + &self, + url: &str, + proxy_type: ProxyType, + timeout_secs: Option, + user_agent: Option, + accept_invalid_certs: bool, + ) -> Result { + let max_retries = 2; + let mut last_error = None; + + for attempt in 0..=max_retries { + if attempt > 0 { + logging!(info, Type::Network, "重试第{}次请求: {}", attempt, url); + tokio::time::sleep(Duration::from_millis(500)).await; + } + + match self + .get( + url, + proxy_type, + timeout_secs, + user_agent.clone(), + accept_invalid_certs, + ) + .await + { + Ok(resp) => return Ok(resp), + Err(e) => { + logging!( + warn, + Type::Network, + "请求失败 (尝试 {}/{}): {} - {}", + attempt + 1, + max_retries + 1, + url, + e + ); + last_error = Some(e); + continue; + } + } + } + + Err(last_error.unwrap_or_else(|| anyhow::anyhow!("请求失败,但没有具体错误信息"))) + } } /// 代理类型