mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 06:53:44 +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()
|
let resp = NetworkManager::global()
|
||||||
.get(
|
.get_with_retry(
|
||||||
url,
|
url,
|
||||||
proxy_type,
|
proxy_type,
|
||||||
Some(timeout),
|
Some(timeout),
|
||||||
|
@ -108,14 +108,29 @@ impl Handle {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已经完成启动,直接发送消息
|
// 使用AsyncHandler发送消息,防止阻塞
|
||||||
if let Some(window) = handle.get_window() {
|
let status_clone = status_str.clone();
|
||||||
logging_error!(
|
let msg_clone = msg_str.clone();
|
||||||
Type::Frontend,
|
|
||||||
true,
|
crate::process::AsyncHandler::spawn(move || async move {
|
||||||
window.emit("verge://notice-message", (status_str, msg_str))
|
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 {
|
for error in errors_clone {
|
||||||
let _ =
|
let _ =
|
||||||
window_clone.emit("verge://notice-message", (error.status, error.message));
|
window_clone.emit("verge://notice-message", (error.status, error.message));
|
||||||
// 每条消息之间间隔500ms,避免消息堆积
|
|
||||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -385,7 +385,6 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修复类型比较,使用字符串值比较而不是引用比较
|
|
||||||
let profile = match items
|
let profile = match items
|
||||||
.iter()
|
.iter()
|
||||||
.find(|item| item.uid.as_ref().map(|u| u.as_str()) == Some(uid))
|
.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
|
/// Emit update events for frontend notification
|
||||||
fn emit_update_event(_uid: &str, _is_start: bool) {
|
fn emit_update_event(_uid: &str, _is_start: bool) {
|
||||||
// 当feature="verge-dev"或"default"时才启用此功能
|
|
||||||
#[cfg(any(feature = "verge-dev", feature = "default"))]
|
#[cfg(any(feature = "verge-dev", feature = "default"))]
|
||||||
{
|
{
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
@ -443,39 +441,44 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Async task with better error handling and logging
|
/// Async task with better error handling and logging
|
||||||
|
|
||||||
async fn async_task(uid: String) {
|
async fn async_task(uid: String) {
|
||||||
let task_start = std::time::Instant::now();
|
let task_start = std::time::Instant::now();
|
||||||
logging!(info, Type::Timer, "Running timer task for profile: {}", uid);
|
logging!(info, Type::Timer, "Running timer task for profile: {}", uid);
|
||||||
|
|
||||||
// Emit start event
|
match tokio::time::timeout(std::time::Duration::from_secs(40), async {
|
||||||
Self::emit_update_event(&uid, true);
|
Self::emit_update_event(&uid, true);
|
||||||
|
|
||||||
// 检查是否是当前激活的配置文件
|
let is_current = Config::profiles().latest().current.as_ref() == Some(&uid);
|
||||||
let is_current = Config::profiles().latest().current.as_ref() == Some(&uid);
|
logging!(
|
||||||
logging!(
|
info,
|
||||||
info,
|
Type::Timer,
|
||||||
Type::Timer,
|
"配置 {} 是否为当前激活配置: {}",
|
||||||
"配置 {} 是否为当前激活配置: {}",
|
uid,
|
||||||
uid,
|
is_current
|
||||||
is_current
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// Update profile - 由update_profile函数自动处理是否需要刷新UI
|
feat::update_profile(uid.clone(), None, Some(is_current)).await
|
||||||
let profile_result = feat::update_profile(uid.clone(), None, Some(is_current)).await;
|
})
|
||||||
|
.await
|
||||||
match profile_result {
|
{
|
||||||
Ok(_) => {
|
Ok(result) => match result {
|
||||||
let duration = task_start.elapsed().as_millis();
|
Ok(_) => {
|
||||||
logging!(
|
let duration = task_start.elapsed().as_millis();
|
||||||
info,
|
logging!(
|
||||||
Type::Timer,
|
info,
|
||||||
"Timer task completed successfully for uid: {} (took {}ms)",
|
Type::Timer,
|
||||||
uid,
|
"Timer task completed successfully for uid: {} (took {}ms)",
|
||||||
duration
|
uid,
|
||||||
);
|
duration
|
||||||
}
|
);
|
||||||
Err(e) => {
|
}
|
||||||
logging_error!(Type::Timer, "Failed to update profile uid {}: {}", uid, e);
|
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
|
.await
|
||||||
.context("Failed to send HTTP request")
|
.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