Refactor session PID types from string to number across backend and extension
- Changed `pid` field in `SessionInfo` from `string` to `number`/`i32` in TypeScript and Rust. - Updated `activeSessions` map key from `string` to `number` to align with new PID type. - Adjusted process monitoring logic to correctly handle numeric PIDs. - Removed fallback UUID-based PID generation in favor of numeric fallback (-1). - Added PID cleanup logic in `is_process_running` when the process is no longer alive. - Bumped application version from 0.5.16 to 0.6.900 in `tauri.conf.json`.
This commit is contained in:
parent
dbdc031583
commit
d4a3d6a0d6
@ -161,7 +161,7 @@ export interface modelInfo {
|
|||||||
export type listResult = modelInfo[]
|
export type listResult = modelInfo[]
|
||||||
|
|
||||||
export interface SessionInfo {
|
export interface SessionInfo {
|
||||||
pid: string // opaque handle for unload/chat
|
pid: number // opaque handle for unload/chat
|
||||||
port: number // llama-server output port (corrected from portid)
|
port: number // llama-server output port (corrected from portid)
|
||||||
model_id: string, //name of the model
|
model_id: string, //name of the model
|
||||||
model_path: string // path of the loaded model
|
model_path: string // path of the loaded model
|
||||||
|
|||||||
@ -114,7 +114,7 @@ export default class llamacpp_extension extends AIEngine {
|
|||||||
readonly providerId: string = 'llamacpp'
|
readonly providerId: string = 'llamacpp'
|
||||||
|
|
||||||
private config: LlamacppConfig
|
private config: LlamacppConfig
|
||||||
private activeSessions: Map<string, SessionInfo> = new Map()
|
private activeSessions: Map<number, SessionInfo> = new Map()
|
||||||
private providerPath!: string
|
private providerPath!: string
|
||||||
private apiSecret: string = 'Jan'
|
private apiSecret: string = 'Jan'
|
||||||
|
|
||||||
@ -724,7 +724,7 @@ export default class llamacpp_extension extends AIEngine {
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
await this.sleep(500) // 500 sec interval during rechecks
|
await this.sleep(500) // 500 sec interval during rechecks
|
||||||
}
|
}
|
||||||
await this.unload(sInfo.pid)
|
await this.unload(sInfo.model_id)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Timed out loading model after ${timeoutMs}... killing llamacpp`
|
`Timed out loading model after ${timeoutMs}... killing llamacpp`
|
||||||
)
|
)
|
||||||
@ -967,10 +967,12 @@ export default class llamacpp_extension extends AIEngine {
|
|||||||
if (!sessionInfo) {
|
if (!sessionInfo) {
|
||||||
throw new Error(`No active session found for model: ${opts.model}`)
|
throw new Error(`No active session found for model: ${opts.model}`)
|
||||||
}
|
}
|
||||||
const result = invoke<boolean>('is_process_running', {
|
// check if the process is alive
|
||||||
|
const result = await invoke<boolean>('is_process_running', {
|
||||||
pid: sessionInfo.pid,
|
pid: sessionInfo.pid,
|
||||||
})
|
})
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
this.activeSessions.delete(sessionInfo.pid)
|
||||||
throw new Error('Model have crashed! Please reload!')
|
throw new Error('Model have crashed! Please reload!')
|
||||||
}
|
}
|
||||||
const baseUrl = `http://localhost:${sessionInfo.port}/v1`
|
const baseUrl = `http://localhost:${sessionInfo.port}/v1`
|
||||||
|
|||||||
@ -24,7 +24,7 @@ pub struct AppState {
|
|||||||
pub mcp_active_servers: Arc<Mutex<HashMap<String, serde_json::Value>>>,
|
pub mcp_active_servers: Arc<Mutex<HashMap<String, serde_json::Value>>>,
|
||||||
pub mcp_successfully_connected: Arc<Mutex<HashMap<String, bool>>>,
|
pub mcp_successfully_connected: Arc<Mutex<HashMap<String, bool>>>,
|
||||||
pub server_handle: Arc<Mutex<Option<ServerHandle>>>,
|
pub server_handle: Arc<Mutex<Option<ServerHandle>>>,
|
||||||
pub llama_server_process: Arc<Mutex<HashMap<String, LLamaBackendSession>>>,
|
pub llama_server_process: Arc<Mutex<HashMap<i32, LLamaBackendSession>>>,
|
||||||
}
|
}
|
||||||
pub fn generate_app_token() -> String {
|
pub fn generate_app_token() -> String {
|
||||||
rand::thread_rng()
|
rand::thread_rng()
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::core::state::AppState;
|
|||||||
|
|
||||||
pub async fn cleanup_processes(state: State<'_, AppState>) {
|
pub async fn cleanup_processes(state: State<'_, AppState>) {
|
||||||
let mut map = state.llama_server_process.lock().await;
|
let mut map = state.llama_server_process.lock().await;
|
||||||
let pids: Vec<String> = map.keys().cloned().collect();
|
let pids: Vec<i32> = map.keys().cloned().collect();
|
||||||
for pid in pids {
|
for pid in pids {
|
||||||
if let Some(session) = map.remove(&pid) {
|
if let Some(session) = map.remove(&pid) {
|
||||||
let mut child = session.child;
|
let mut child = session.child;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ use tauri::State; // Import Manager trait
|
|||||||
use thiserror;
|
use thiserror;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::core::state::AppState;
|
use crate::core::state::AppState;
|
||||||
use crate::core::state::LLamaBackendSession;
|
use crate::core::state::LLamaBackendSession;
|
||||||
@ -44,8 +43,8 @@ type ServerResult<T> = Result<T, ServerError>;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SessionInfo {
|
pub struct SessionInfo {
|
||||||
pub pid: String, // opaque handle for unload/chat
|
pub pid: i32, // opaque handle for unload/chat
|
||||||
pub port: String, // llama-server output port
|
pub port: i32, // llama-server output port
|
||||||
pub model_id: String,
|
pub model_id: String,
|
||||||
pub model_path: String, // path of the loaded model
|
pub model_path: String, // path of the loaded model
|
||||||
pub api_key: String,
|
pub api_key: String,
|
||||||
@ -82,12 +81,19 @@ pub async fn load_llama_model(
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let port = args
|
let port_str = args
|
||||||
.iter()
|
.iter()
|
||||||
.position(|arg| arg == "--port")
|
.position(|arg| arg == "--port")
|
||||||
.and_then(|i| args.get(i + 1))
|
.and_then(|i| args.get(i + 1))
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let port: i32 = match port_str.parse() {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("Invalid port value: '{}', using default 8080", port_str);
|
||||||
|
8080
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let model_path = args
|
let model_path = args
|
||||||
.iter()
|
.iter()
|
||||||
@ -146,10 +152,7 @@ pub async fn load_llama_model(
|
|||||||
let child = command.spawn().map_err(ServerError::Io)?;
|
let child = command.spawn().map_err(ServerError::Io)?;
|
||||||
|
|
||||||
// Get the PID to use as session ID
|
// Get the PID to use as session ID
|
||||||
let pid = child.id().map(|id| id.to_string()).unwrap_or_else(|| {
|
let pid = child.id().map(|id| id as i32).unwrap_or(-1);
|
||||||
// Fallback in case we can't get the PID for some reason
|
|
||||||
format!("unknown_pid_{}", Uuid::new_v4())
|
|
||||||
});
|
|
||||||
|
|
||||||
log::info!("Server process started with PID: {}", pid);
|
log::info!("Server process started with PID: {}", pid);
|
||||||
let session_info = SessionInfo {
|
let session_info = SessionInfo {
|
||||||
@ -175,7 +178,7 @@ pub async fn load_llama_model(
|
|||||||
// --- Unload Command ---
|
// --- Unload Command ---
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn unload_llama_model(
|
pub async fn unload_llama_model(
|
||||||
pid: String,
|
pid: i32,
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
) -> ServerResult<UnloadResult> {
|
) -> ServerResult<UnloadResult> {
|
||||||
let mut map = state.llama_server_process.lock().await;
|
let mut map = state.llama_server_process.lock().await;
|
||||||
@ -212,9 +215,7 @@ pub async fn unload_llama_model(
|
|||||||
|
|
||||||
if let Some(raw_pid) = child.id() {
|
if let Some(raw_pid) = child.id() {
|
||||||
log::info!("Sending Ctrl-C to PID {}", raw_pid);
|
log::info!("Sending Ctrl-C to PID {}", raw_pid);
|
||||||
let ok: i32 = unsafe {
|
let ok: i32 = unsafe { GenerateConsoleCtrlEvent(CTRL_C_EVENT, raw_pid as u32) };
|
||||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, raw_pid as u32)
|
|
||||||
};
|
|
||||||
if ok == 0 {
|
if ok == 0 {
|
||||||
log::error!("Failed to send Ctrl-C to PID {}", raw_pid);
|
log::error!("Failed to send Ctrl-C to PID {}", raw_pid);
|
||||||
}
|
}
|
||||||
@ -266,9 +267,17 @@ pub fn generate_api_key(model_id: String, api_secret: String) -> Result<String,
|
|||||||
|
|
||||||
// process aliveness check
|
// process aliveness check
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn is_process_running(pid: u32) -> Result<bool, String> {
|
pub async fn is_process_running(pid: i32, state: State<'_, AppState>) -> Result<bool, String> {
|
||||||
let mut system = System::new();
|
let mut system = System::new();
|
||||||
system.refresh_processes(ProcessesToUpdate::All, true);
|
system.refresh_processes(ProcessesToUpdate::All, true);
|
||||||
let process_pid = Pid::from(pid as usize);
|
let process_pid = Pid::from(pid as usize);
|
||||||
Ok(system.process(process_pid).is_some())
|
let alive = system.process(process_pid).is_some();
|
||||||
|
|
||||||
|
if !alive {
|
||||||
|
let mut map = state.llama_server_process.lock().await;
|
||||||
|
map.remove(&pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(alive)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Jan",
|
"productName": "Jan",
|
||||||
"version": "0.5.16",
|
"version": "0.6.900",
|
||||||
"identifier": "jan.ai.app",
|
"identifier": "jan.ai.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../web-app/dist",
|
"frontendDist": "../web-app/dist",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user