mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 00:53:45 +08:00
feat: add retry mechanism to optimize network requests, improve async message handling and timeout for scheduled tasks
This commit is contained in:
parent
e7bf997f8c
commit
73b9a71c84
@ -265,7 +265,7 @@ impl PrfItem {
|
||||
|
||||
// 使用网络管理器发送请求
|
||||
let resp = NetworkManager::global()
|
||||
.get(
|
||||
.get_with_retry(
|
||||
url,
|
||||
proxy_type,
|
||||
Some(timeout),
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<u64>,
|
||||
user_agent: Option<String>,
|
||||
accept_invalid_certs: bool,
|
||||
) -> Result<Response> {
|
||||
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!("请求失败,但没有具体错误信息")))
|
||||
}
|
||||
}
|
||||
|
||||
/// 代理类型
|
||||
|
Loading…
x
Reference in New Issue
Block a user