fix: add cortex_killed_intentionally state to manage sidecar process termination (#5255)

* fix: add cortex_killed_intentionally state to manage sidecar process termination

* fix: improve handling of intentionally killed sidecar process
This commit is contained in:
Sam Hoang Van 2025-06-12 19:20:27 +07:00 committed by GitHub
parent 32f68de36f
commit e22452b26e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 10 deletions

View File

@ -10,8 +10,8 @@ use tauri::{App, Emitter, Listener, Manager};
use tauri_plugin_shell::process::{CommandChild, CommandEvent}; use tauri_plugin_shell::process::{CommandChild, CommandEvent};
use tauri_plugin_shell::ShellExt; use tauri_plugin_shell::ShellExt;
use tauri_plugin_store::StoreExt; use tauri_plugin_store::StoreExt;
use tokio::time::{sleep, Duration}; use tokio::sync::Mutex;
use tokio::{sync::Mutex}; // Using tokio::sync::Mutex use tokio::time::{sleep, Duration}; // Using tokio::sync::Mutex
// MCP // MCP
use super::{ use super::{
cmd::{get_jan_data_folder_path, get_jan_extensions_path}, cmd::{get_jan_data_folder_path, get_jan_extensions_path},
@ -220,6 +220,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
let app_state = app_handle_for_spawn.state::<AppState>(); let app_state = app_handle_for_spawn.state::<AppState>();
let cortex_restart_count_state = app_state.cortex_restart_count.clone(); let cortex_restart_count_state = app_state.cortex_restart_count.clone();
let cortex_killed_intentionally_state = app_state.cortex_killed_intentionally.clone();
let app_data_dir = get_jan_data_folder_path(app_handle_for_spawn.clone()); let app_data_dir = get_jan_data_folder_path(app_handle_for_spawn.clone());
let sidecar_command_builder = || { let sidecar_command_builder = || {
@ -274,9 +275,11 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
let child_to_kill_arc = child_process_clone_for_kill.clone(); let child_to_kill_arc = child_process_clone_for_kill.clone();
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
let app_state = app_handle.state::<AppState>(); let app_state = app_handle.state::<AppState>();
let mut count = app_state.cortex_restart_count.lock().await; // Mark as intentionally killed to prevent restart
*count = 5; let mut killed_intentionally = app_state.cortex_killed_intentionally.lock().await;
drop(count); *killed_intentionally = true;
drop(killed_intentionally);
log::info!("Received kill-sidecar event (processing async)."); log::info!("Received kill-sidecar event (processing async).");
if let Some(child) = child_to_kill_arc.lock().await.take() { if let Some(child) = child_to_kill_arc.lock().await.take() {
log::info!("Attempting to kill sidecar process..."); log::info!("Attempting to kill sidecar process...");
@ -329,6 +332,19 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
); );
*count = 0; *count = 0;
} }
drop(count);
// Only reset the intentionally killed flag if it wasn't set during spawn
// This prevents overriding a concurrent kill event
let mut killed_intentionally =
cortex_killed_intentionally_state.lock().await;
if !*killed_intentionally {
// Flag wasn't set during spawn, safe to reset for future cycles
*killed_intentionally = false;
} else {
log::info!("Kill intent detected during spawn, preserving kill flag");
}
drop(killed_intentionally);
} }
let mut process_terminated_unexpectedly = false; let mut process_terminated_unexpectedly = false;
@ -373,7 +389,13 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
log::info!("Cleared child process lock after termination."); log::info!("Cleared child process lock after termination.");
} }
if process_terminated_unexpectedly { // Check if the process was killed intentionally
let killed_intentionally = *cortex_killed_intentionally_state.lock().await;
if killed_intentionally {
log::info!("Cortex server was killed intentionally. Not restarting.");
break;
} else if process_terminated_unexpectedly {
log::warn!("Cortex server terminated unexpectedly."); log::warn!("Cortex server terminated unexpectedly.");
let mut count = cortex_restart_count_state.lock().await; let mut count = cortex_restart_count_state.lock().await;
*count += 1; *count += 1;
@ -387,9 +409,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> {
sleep(Duration::from_millis(RESTART_DELAY_MS)).await; sleep(Duration::from_millis(RESTART_DELAY_MS)).await;
continue; continue;
} else { } else {
log::info!( log::info!("Cortex server terminated normally. Not restarting.");
"Cortex server terminated normally or was killed. Not restarting."
);
break; break;
} }
} }

View File

@ -11,6 +11,7 @@ pub struct AppState {
pub mcp_servers: Arc<Mutex<HashMap<String, RunningService<RoleClient, ()>>>>, pub mcp_servers: Arc<Mutex<HashMap<String, RunningService<RoleClient, ()>>>>,
pub download_manager: Arc<Mutex<DownloadManagerState>>, pub download_manager: Arc<Mutex<DownloadManagerState>>,
pub cortex_restart_count: Arc<Mutex<u32>>, pub cortex_restart_count: Arc<Mutex<u32>>,
pub cortex_killed_intentionally: Arc<Mutex<bool>>,
} }
pub fn generate_app_token() -> String { pub fn generate_app_token() -> String {
rand::thread_rng() rand::thread_rng()

View File

@ -91,6 +91,7 @@ pub fn run() {
mcp_servers: Arc::new(Mutex::new(HashMap::new())), mcp_servers: Arc::new(Mutex::new(HashMap::new())),
download_manager: Arc::new(Mutex::new(DownloadManagerState::default())), download_manager: Arc::new(Mutex::new(DownloadManagerState::default())),
cortex_restart_count: Arc::new(Mutex::new(0)), cortex_restart_count: Arc::new(Mutex::new(0)),
cortex_killed_intentionally: Arc::new(Mutex::new(false)),
}) })
.setup(|app| { .setup(|app| {
app.handle().plugin( app.handle().plugin(