fix: Update server process handling for Windows and Unix systems
This commit is contained in:
parent
7dbc2c3af2
commit
01d49a4b28
@ -57,6 +57,8 @@ hmac = "0.12.1"
|
||||
sha2 = "0.10.9"
|
||||
base64 = "0.22.1"
|
||||
libloading = "0.8.7"
|
||||
thiserror = "2.0.12"
|
||||
nix = "=0.30.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
libc = "0.2.172"
|
||||
@ -65,4 +67,3 @@ libc = "0.2.172"
|
||||
tauri-plugin-updater = "2"
|
||||
once_cell = "1.18"
|
||||
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
|
||||
thiserror = "2.0.12"
|
||||
|
||||
@ -7,6 +7,8 @@ use tauri::State; // Import Manager trait
|
||||
use thiserror;
|
||||
use tokio::process::Command;
|
||||
use uuid::Uuid;
|
||||
use std::time::Duration;
|
||||
use tokio::time::timeout;
|
||||
|
||||
use crate::core::state::AppState;
|
||||
|
||||
@ -131,6 +133,10 @@ pub async fn load_llama_model(
|
||||
// Optional: Redirect stdio if needed (e.g., for logging within Jan)
|
||||
// command.stdout(Stdio::piped());
|
||||
// command.stderr(Stdio::piped());
|
||||
#[cfg(windows)]
|
||||
{
|
||||
command.creation_flags(CREATE_NEW_PROCESS_GROUP);
|
||||
}
|
||||
|
||||
// Spawn the child process
|
||||
let child = command.spawn().map_err(ServerError::Io)?;
|
||||
@ -163,47 +169,69 @@ pub async fn unload_llama_model(
|
||||
pid: String,
|
||||
state: State<'_, AppState>,
|
||||
) -> ServerResult<UnloadResult> {
|
||||
let mut process_map = state.llama_server_process.lock().await;
|
||||
match process_map.remove(&pid) {
|
||||
Some(mut child) => {
|
||||
log::info!("Terminating server process with PID: {}", pid);
|
||||
let mut map = state.llama_server_process.lock().await;
|
||||
if let Some(mut child) = map.remove(&pid) {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use nix::unistd::Pid;
|
||||
|
||||
// 1. Send the kill signal
|
||||
if let Err(e) = child.kill().await {
|
||||
log::error!("Failed to send kill to server process: {}", e);
|
||||
return Ok(UnloadResult {
|
||||
success: false,
|
||||
error: Some(format!("kill failed: {}", e)),
|
||||
});
|
||||
}
|
||||
if let Some(raw_pid) = child.id() {
|
||||
let raw_pid = raw_pid as i32;
|
||||
log::info!("Sending SIGTERM to PID {}", raw_pid);
|
||||
let _ = kill(Pid::from_raw(raw_pid), Signal::SIGTERM);
|
||||
|
||||
// 2. Await its exit so the OS can reap it
|
||||
match timeout(Duration::from_secs(5), child.wait()).await {
|
||||
Ok(Ok(status)) => log::info!("Process exited gracefully: {}", status),
|
||||
Ok(Err(e)) => log::error!("Error waiting after SIGTERM: {}", e),
|
||||
Err(_) => {
|
||||
log::warn!("SIGTERM timed out; sending SIGKILL to PID {}", raw_pid);
|
||||
let _ = kill(Pid::from_raw(raw_pid), Signal::SIGKILL);
|
||||
match child.wait().await {
|
||||
Ok(exit_status) => {
|
||||
log::info!("Server exited with: {}", exit_status);
|
||||
Ok(UnloadResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Error waiting for server process: {}", e);
|
||||
Ok(UnloadResult {
|
||||
success: false,
|
||||
error: Some(format!("wait failed: {}", e)),
|
||||
})
|
||||
Ok(s) => log::info!("Force-killed process exited: {}", s),
|
||||
Err(e) => log::error!("Error waiting after SIGKILL: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::warn!("No server with PID '{}' found to unload", pid);
|
||||
Ok(UnloadResult {
|
||||
success: true,
|
||||
error: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use windows_sys::Win32::System::Console::{GenerateConsoleCtrlEvent, CTRL_C_EVENT};
|
||||
use windows_sys::Win32::Foundation::BOOL;
|
||||
|
||||
if let Some(raw_pid) = child.id() {
|
||||
log::info!("Sending Ctrl-C to PID {}", raw_pid);
|
||||
let ok: BOOL = unsafe { GenerateConsoleCtrlEvent(CTRL_C_EVENT, raw_pid) };
|
||||
if ok == 0 {
|
||||
log::error!("Failed to send Ctrl-C to PID {}", raw_pid);
|
||||
}
|
||||
|
||||
match timeout(Duration::from_secs(5), child.wait()).await {
|
||||
Ok(Ok(status)) => log::info!("Process exited after Ctrl-C: {}", status),
|
||||
Ok(Err(e)) => log::error!("Error waiting after Ctrl-C: {}", e),
|
||||
Err(_) => {
|
||||
log::warn!("Timed out; force-killing PID {}", raw_pid);
|
||||
if let Err(e) = child.kill().await {
|
||||
log::error!("Failed to kill process {}: {}", raw_pid, e);
|
||||
return Ok(UnloadResult { success: false, error: Some(format!("kill failed: {}", e)) });
|
||||
}
|
||||
if let Ok(s) = child.wait().await {
|
||||
log::info!("Process finally exited: {}", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(UnloadResult { success: true, error: None })
|
||||
} else {
|
||||
log::warn!("No server with PID '{}' found", pid);
|
||||
Ok(UnloadResult { success: true, error: None })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// crypto
|
||||
#[tauri::command]
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
mod core;
|
||||
use reqwest::Client;
|
||||
use core::{
|
||||
cmd::get_jan_data_folder_path,
|
||||
setup::{self, setup_mcp},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user