refactor: Replace tokio::spawn with AsyncHandler::spawn for better task management

- Replace direct tokio::spawn calls with AsyncHandler::spawn across multiple modules
- Improves task lifecycle management and error handling consistency
- Affected files:
  - src-tauri/src/cmd/network.rs
  - src-tauri/src/core/core.rs
  - src-tauri/src/core/event_driven_proxy.rs
  - src-tauri/src/enhance/tun.rs
  - src-tauri/src/ipc/logs.rs
  - src-tauri/src/ipc/memory.rs
  - src-tauri/src/ipc/monitor.rs
  - src-tauri/src/ipc/traffic.rs
  - src-tauri/src/utils/network.rs
  - src-tauri/src/utils/resolve.rs

This change provides better control over async task spawning and helps prevent
potential issues with unmanaged background tasks.
This commit is contained in:
Tunglies
2025-08-22 03:41:14 +08:00
parent 02f67961a9
commit e4c243de2d
10 changed files with 29 additions and 16 deletions

View File

@@ -1,5 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::core::{async_proxy_query::AsyncProxyQuery, EventDrivenProxyManager}; use crate::core::{async_proxy_query::AsyncProxyQuery, EventDrivenProxyManager};
use crate::process::AsyncHandler;
use crate::wrap_err; use crate::wrap_err;
use network_interface::NetworkInterface; use network_interface::NetworkInterface;
use serde_yaml::Mapping; use serde_yaml::Mapping;
@@ -32,7 +33,7 @@ pub async fn get_auto_proxy() -> CmdResult<Mapping> {
let current = proxy_manager.get_auto_proxy_cached(); let current = proxy_manager.get_auto_proxy_cached();
// 异步请求更新,立即返回缓存数据 // 异步请求更新,立即返回缓存数据
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
let _ = proxy_manager.get_auto_proxy_async().await; let _ = proxy_manager.get_auto_proxy_async().await;
}); });

View File

@@ -5,7 +5,9 @@ use crate::{
service::{self}, service::{self},
}, },
ipc::IpcManager, ipc::IpcManager,
logging, logging_error, singleton_lazy, logging, logging_error,
process::AsyncHandler,
singleton_lazy,
utils::{ utils::{
dirs, dirs,
help::{self}, help::{self},
@@ -763,7 +765,7 @@ impl CoreManager {
]) ])
.spawn()?; .spawn()?;
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event { if let tauri_plugin_shell::process::CommandEvent::Stdout(line) = event {
if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) { if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) {

View File

@@ -7,6 +7,7 @@ use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use crate::config::{Config, IVerge}; use crate::config::{Config, IVerge};
use crate::core::async_proxy_query::AsyncProxyQuery; use crate::core::async_proxy_query::AsyncProxyQuery;
use crate::logging_error; use crate::logging_error;
use crate::process::AsyncHandler;
use crate::utils::logging::Type; use crate::utils::logging::Type;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use sysproxy::{Autoproxy, Sysproxy}; use sysproxy::{Autoproxy, Sysproxy};
@@ -176,7 +177,7 @@ impl EventDrivenProxyManager {
event_rx: mpsc::UnboundedReceiver<ProxyEvent>, event_rx: mpsc::UnboundedReceiver<ProxyEvent>,
query_rx: mpsc::UnboundedReceiver<QueryRequest>, query_rx: mpsc::UnboundedReceiver<QueryRequest>,
) { ) {
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
log::info!(target: "app", "事件驱动代理管理器启动"); log::info!(target: "app", "事件驱动代理管理器启动");
// 将 mpsc 接收器包装成 Stream避免每次循环创建 future // 将 mpsc 接收器包装成 Stream避免每次循环创建 future

View File

@@ -1,5 +1,8 @@
use serde_yaml::{Mapping, Value}; use serde_yaml::{Mapping, Value};
#[cfg(target_os = "macos")]
use crate::process::AsyncHandler;
macro_rules! revise { macro_rules! revise {
($map: expr, $key: expr, $val: expr) => { ($map: expr, $key: expr, $val: expr) => {
let ret_key = Value::String($key.into()); let ret_key = Value::String($key.into());
@@ -59,7 +62,7 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
tokio::spawn(async { AsyncHandler::spawn(move || async move {
crate::utils::resolve::restore_public_dns().await; crate::utils::resolve::restore_public_dns().await;
crate::utils::resolve::set_public_dns("223.6.6.6".to_string()).await; crate::utils::resolve::set_public_dns("223.6.6.6".to_string()).await;
}); });
@@ -71,7 +74,7 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
} else { } else {
// TUN未启用时仅恢复系统DNS不修改配置文件中的DNS设置 // TUN未启用时仅恢复系统DNS不修改配置文件中的DNS设置
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
tokio::spawn(async { AsyncHandler::spawn(move || async move {
crate::utils::resolve::restore_public_dns().await; crate::utils::resolve::restore_public_dns().await;
}); });
} }

View File

@@ -1,10 +1,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::VecDeque, sync::Arc, time::Instant}; use std::{collections::VecDeque, sync::Arc, time::Instant};
use tokio::{sync::RwLock, task::JoinHandle, time::Duration}; use tauri::async_runtime::JoinHandle;
use tokio::{sync::RwLock, time::Duration};
use crate::{ use crate::{
ipc::monitor::MonitorData, ipc::monitor::MonitorData,
logging, singleton_with_logging, logging,
process::AsyncHandler,
singleton_with_logging,
utils::{dirs::ipc_path, logging::Type}, utils::{dirs::ipc_path, logging::Type},
}; };
@@ -159,7 +162,7 @@ impl LogsMonitor {
let monitor_current = Arc::clone(&self.current); let monitor_current = Arc::clone(&self.current);
let task = tokio::spawn(async move { let task = AsyncHandler::spawn(move || async move {
loop { loop {
// Get fresh IPC path and client for each connection attempt // Get fresh IPC path and client for each connection attempt
let (_ipc_path_buf, client) = match Self::create_ipc_client() { let (_ipc_path_buf, client) = match Self::create_ipc_client() {
@@ -256,7 +259,7 @@ impl LogsMonitor {
// We only need to accept all logs since filtering is done at the endpoint level // We only need to accept all logs since filtering is done at the endpoint level
let log_item = LogItem::new(log_data.log_type, log_data.payload); let log_item = LogItem::new(log_data.log_type, log_data.payload);
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
let mut logs = current.write().await; let mut logs = current.write().await;
// Add new log // Add new log

View File

@@ -4,6 +4,7 @@ use tokio::{sync::RwLock, time::Duration};
use crate::{ use crate::{
ipc::monitor::{IpcStreamMonitor, MonitorData, StreamingParser}, ipc::monitor::{IpcStreamMonitor, MonitorData, StreamingParser},
process::AsyncHandler,
singleton_lazy_with_logging, singleton_lazy_with_logging,
utils::format::fmt_bytes, utils::format::fmt_bytes,
}; };
@@ -47,7 +48,7 @@ impl StreamingParser for CurrentMemory {
current: Arc<RwLock<Self>>, current: Arc<RwLock<Self>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if let Ok(memory) = serde_json::from_str::<MemoryData>(line.trim()) { if let Ok(memory) = serde_json::from_str::<MemoryData>(line.trim()) {
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
let mut current_guard = current.write().await; let mut current_guard = current.write().await;
current_guard.inuse = memory.inuse; current_guard.inuse = memory.inuse;
current_guard.oslimit = memory.oslimit; current_guard.oslimit = memory.oslimit;

View File

@@ -4,6 +4,7 @@ use tokio::{sync::RwLock, time::Duration};
use crate::{ use crate::{
logging, logging,
process::AsyncHandler,
utils::{dirs::ipc_path, logging::Type}, utils::{dirs::ipc_path, logging::Type},
}; };
@@ -55,7 +56,7 @@ where
let endpoint_clone = endpoint.clone(); let endpoint_clone = endpoint.clone();
// Start the monitoring task // Start the monitoring task
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
Self::streaming_task(monitor_current, endpoint_clone, timeout, retry_interval).await; Self::streaming_task(monitor_current, endpoint_clone, timeout, retry_interval).await;
}); });

View File

@@ -4,6 +4,7 @@ use tokio::{sync::RwLock, time::Duration};
use crate::{ use crate::{
ipc::monitor::{IpcStreamMonitor, MonitorData, StreamingParser}, ipc::monitor::{IpcStreamMonitor, MonitorData, StreamingParser},
process::AsyncHandler,
singleton_lazy_with_logging, singleton_lazy_with_logging,
utils::format::fmt_bytes, utils::format::fmt_bytes,
}; };
@@ -68,7 +69,7 @@ impl StreamingParser for TrafficMonitorState {
current: Arc<RwLock<Self>>, current: Arc<RwLock<Self>>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if let Ok(traffic) = serde_json::from_str::<TrafficData>(line.trim()) { if let Ok(traffic) = serde_json::from_str::<TrafficData>(line.trim()) {
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
let mut state_guard = current.write().await; let mut state_guard = current.write().await;
let (up_rate, down_rate) = state_guard let (up_rate, down_rate) = state_guard

View File

@@ -10,7 +10,7 @@ use std::{
}; };
use tokio::runtime::{Builder, Runtime}; use tokio::runtime::{Builder, Runtime};
use crate::{config::Config, logging, singleton_lazy, utils::logging::Type}; use crate::{config::Config, logging, process::AsyncHandler, singleton_lazy, utils::logging::Type};
// HTTP2 相关 // HTTP2 相关
const H2_CONNECTION_WINDOW_SIZE: u32 = 1024 * 1024; const H2_CONNECTION_WINDOW_SIZE: u32 = 1024 * 1024;
@@ -351,7 +351,7 @@ impl NetworkManager {
let (cancel_tx, cancel_rx) = tokio::sync::oneshot::channel::<()>(); let (cancel_tx, cancel_rx) = tokio::sync::oneshot::channel::<()>();
let url_clone = url.to_string(); let url_clone = url.to_string();
let watchdog = tokio::spawn(async move { let watchdog = AsyncHandler::spawn(move || async move {
tokio::time::sleep(Duration::from_secs(timeout_duration)).await; tokio::time::sleep(Duration::from_secs(timeout_duration)).await;
let _ = cancel_tx.send(()); let _ = cancel_tx.send(());
logging!(warn, Type::Network, true, "请求超时取消: {}", url_clone); logging!(warn, Type::Network, true, "请求超时取消: {}", url_clone);

View File

@@ -460,7 +460,7 @@ pub fn create_window(is_show: bool) -> bool {
); );
// 异步监控UI状态使用try_read避免死锁 // 异步监控UI状态使用try_read避免死锁
tokio::spawn(async move { AsyncHandler::spawn(move || async move {
logging!( logging!(
debug, debug,
Type::Window, Type::Window,