性能优化
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use serde::Serialize;
|
||||
use specta::Type;
|
||||
use std::collections::HashMap;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::Mutex;
|
||||
@@ -80,7 +81,7 @@ fn get_job_handle() -> Option<winapi::HANDLE> {
|
||||
unsafe {
|
||||
let h = winapi::CreateJobObjectW(std::ptr::null_mut(), std::ptr::null());
|
||||
if h.is_null() {
|
||||
eprintln!("[ProcessManager] CreateJobObjectW 失败,异常退出时子进程可能残留");
|
||||
crate::logger::log_error("process", "CreateJobObjectW 失败,异常退出时子进程可能残留");
|
||||
return 0;
|
||||
}
|
||||
// 设置 KILL_ON_JOB_CLOSE:主进程退出时自动终止所有子进程
|
||||
@@ -93,7 +94,7 @@ fn get_job_handle() -> Option<winapi::HANDLE> {
|
||||
std::mem::size_of::<winapi::JOBOBJECT_EXTENDED_LIMIT_INFORMATION>() as u32,
|
||||
);
|
||||
if ok == 0 {
|
||||
eprintln!("[ProcessManager] SetInformationJobObject 失败");
|
||||
crate::logger::log_error("process", "SetInformationJobObject 失败");
|
||||
return 0;
|
||||
}
|
||||
h as usize
|
||||
@@ -136,7 +137,7 @@ fn assign_to_job(child: &Child) {
|
||||
fn assign_to_job(_child: &Child) {}
|
||||
|
||||
/// 进程状态枚举
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
#[derive(Serialize, Clone, Debug, Type)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ProcessStatus {
|
||||
Running,
|
||||
@@ -147,7 +148,8 @@ pub enum ProcessStatus {
|
||||
}
|
||||
|
||||
/// 进程信息(返回给前端)
|
||||
#[derive(Serialize, Clone)]
|
||||
#[derive(Serialize, Clone, Type)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProcessInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
@@ -291,7 +293,7 @@ impl ProcessManager {
|
||||
Ok(Some(_)) => break,
|
||||
Ok(None) => {
|
||||
if std::time::Instant::now() >= deadline {
|
||||
println!("[ProcessManager] 进程 {} 等待退出超时(3s),放弃等待", id);
|
||||
crate::logger::log_warn("process", &format!("进程 {} 等待退出超时(3s),放弃等待", id));
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
@@ -299,7 +301,7 @@ impl ProcessManager {
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
println!("[ProcessManager] 已停止进程: {}", id);
|
||||
crate::logger::log_info("process", &format!("已停止进程: {}", id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,18 +353,24 @@ impl ProcessManager {
|
||||
|
||||
/// 检查所有进程,处理崩溃的进程(自动重启或移除)
|
||||
/// 返回状态发生变化的进程列表
|
||||
/// 注意:kill/wait/sleep(800ms) 等阻塞操作一律在锁外执行,
|
||||
/// 锁内仅做非阻塞的 try_wait 判定,避免阻塞其他进程的状态查询
|
||||
pub fn check_and_cleanup(&self) -> Vec<ProcessInfo> {
|
||||
let mut changes = Vec::new();
|
||||
// 需要重启的条目(锁外执行 kill + sleep + spawn)
|
||||
let mut restarts: Vec<(String, ProcessEntry)> = Vec::new();
|
||||
|
||||
let mut processes = match self.processes.lock() {
|
||||
Ok(p) => p,
|
||||
Err(_) => return changes,
|
||||
};
|
||||
// 阶段 1:锁内快速判定(仅非阻塞 try_wait),收集重启/移除决策
|
||||
{
|
||||
let mut processes = match self.processes.lock() {
|
||||
Ok(p) => p,
|
||||
Err(_) => return changes,
|
||||
};
|
||||
|
||||
let ids: Vec<String> = processes.keys().cloned().collect();
|
||||
let ids: Vec<String> = processes.keys().cloned().collect();
|
||||
|
||||
for id in ids {
|
||||
if let Some(entry) = processes.get_mut(&id) {
|
||||
for id in ids {
|
||||
let Some(entry) = processes.get_mut(&id) else { continue };
|
||||
match entry.child.try_wait() {
|
||||
Ok(None) => {
|
||||
// 仍在运行,无需处理
|
||||
@@ -373,58 +381,10 @@ impl ProcessManager {
|
||||
&& (entry.max_restarts == 0
|
||||
|| entry.restart_count < entry.max_restarts)
|
||||
{
|
||||
// 自动重启
|
||||
let restart_count = entry.restart_count + 1;
|
||||
let executable = entry.executable.clone();
|
||||
let args = entry.args.clone();
|
||||
let cwd = entry.cwd.clone();
|
||||
let name = entry.name.clone();
|
||||
|
||||
// 先终止旧进程
|
||||
let _ = entry.child.kill();
|
||||
let _ = entry.child.wait();
|
||||
// 等待 TCP 端口释放(Windows 上 kill 后端口释放有延迟)
|
||||
std::thread::sleep(std::time::Duration::from_millis(800));
|
||||
|
||||
// 重新启动
|
||||
let mut cmd = Command::new(&executable);
|
||||
cmd.args(&args);
|
||||
if let Some(ref dir) = cwd {
|
||||
cmd.current_dir(dir);
|
||||
}
|
||||
cmd.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdin(Stdio::null());
|
||||
setup_creation_flags(&mut cmd);
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(new_child) => {
|
||||
let pid = new_child.id();
|
||||
entry.child = new_child;
|
||||
entry.restart_count = restart_count;
|
||||
|
||||
changes.push(ProcessInfo {
|
||||
id: id.clone(),
|
||||
name: name.clone(),
|
||||
status: ProcessStatus::Running,
|
||||
pid: Some(pid),
|
||||
restart_count,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"[ProcessManager] 重启进程 '{}' 失败: {}",
|
||||
id, e
|
||||
);
|
||||
processes.remove(&id);
|
||||
changes.push(ProcessInfo {
|
||||
id: id.clone(),
|
||||
name,
|
||||
status: ProcessStatus::Crashed,
|
||||
pid: None,
|
||||
restart_count,
|
||||
});
|
||||
}
|
||||
// 需要自动重启:从 map 移除,锁外执行
|
||||
if let Some(mut e) = processes.remove(&id) {
|
||||
e.restart_count += 1;
|
||||
restarts.push((id.clone(), e));
|
||||
}
|
||||
} else {
|
||||
// 不自动重启,移除记录
|
||||
@@ -455,6 +415,58 @@ impl ProcessManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // 锁在此释放
|
||||
|
||||
// 阶段 2:锁外执行重启(kill + wait + 端口释放等待 + spawn,不阻塞进程状态查询)
|
||||
for (id, mut entry) in restarts {
|
||||
// 先终止旧进程
|
||||
let _ = entry.child.kill();
|
||||
let _ = entry.child.wait();
|
||||
// 等待 TCP 端口释放(Windows 上 kill 后端口释放有延迟)
|
||||
std::thread::sleep(std::time::Duration::from_millis(800));
|
||||
|
||||
// 重新启动
|
||||
let mut cmd = Command::new(&entry.executable);
|
||||
cmd.args(&entry.args);
|
||||
if let Some(ref dir) = entry.cwd {
|
||||
cmd.current_dir(dir);
|
||||
}
|
||||
cmd.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdin(Stdio::null());
|
||||
setup_creation_flags(&mut cmd);
|
||||
|
||||
let name = entry.name.clone();
|
||||
let restart_count = entry.restart_count;
|
||||
match cmd.spawn() {
|
||||
Ok(new_child) => {
|
||||
let pid = new_child.id();
|
||||
entry.child = new_child;
|
||||
if let Ok(mut processes) = self.processes.lock() {
|
||||
processes.insert(id.clone(), entry);
|
||||
}
|
||||
changes.push(ProcessInfo {
|
||||
id: id.clone(),
|
||||
name,
|
||||
status: ProcessStatus::Running,
|
||||
pid: Some(pid),
|
||||
restart_count,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
crate::logger::log_error(
|
||||
"process",
|
||||
&format!("重启进程 '{}' 失败: {}", id, e),
|
||||
);
|
||||
changes.push(ProcessInfo {
|
||||
id: id.clone(),
|
||||
name,
|
||||
status: ProcessStatus::Crashed,
|
||||
pid: None,
|
||||
restart_count,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changes
|
||||
@@ -464,7 +476,7 @@ impl ProcessManager {
|
||||
// ===== Tauri 命令 =====
|
||||
|
||||
#[tauri::command]
|
||||
pub fn start_process(
|
||||
pub fn process_start(
|
||||
state: tauri::State<'_, ProcessManager>,
|
||||
params: StartProcessParams,
|
||||
) -> Result<ProcessInfo, String> {
|
||||
@@ -472,7 +484,7 @@ pub fn start_process(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn stop_process(
|
||||
pub fn process_stop(
|
||||
state: tauri::State<'_, ProcessManager>,
|
||||
id: String,
|
||||
) -> Result<(), String> {
|
||||
@@ -480,7 +492,7 @@ pub fn stop_process(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_process_status(
|
||||
pub fn process_status(
|
||||
state: tauri::State<'_, ProcessManager>,
|
||||
id: String,
|
||||
) -> Option<ProcessInfo> {
|
||||
@@ -488,14 +500,14 @@ pub fn get_process_status(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_all_process_status(
|
||||
pub fn process_all_status(
|
||||
state: tauri::State<'_, ProcessManager>,
|
||||
) -> Vec<ProcessInfo> {
|
||||
state.get_all_status()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn stop_all_processes(state: tauri::State<'_, ProcessManager>) {
|
||||
pub fn process_stop_all(state: tauri::State<'_, ProcessManager>) {
|
||||
state.stop_all()
|
||||
}
|
||||
|
||||
@@ -509,7 +521,7 @@ pub fn start_monitoring_thread(app: AppHandle) {
|
||||
let changes = state.check_and_cleanup();
|
||||
|
||||
for change in changes {
|
||||
let _ = app.emit("process-status-changed", &change);
|
||||
let _ = app.emit(crate::constants::events::PROCESS_STATUS_CHANGED, &change);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user