From 39e85ff6e4ebcb6e2d2633ba425d930e1b213e8b Mon Sep 17 00:00:00 2001 From: Vimal Date: Mon, 5 Jan 2026 17:15:01 +0800 Subject: [PATCH] fix(desktop): prevent orphaned sidecar processes and add single-instance protection Two fixes for the desktop app spawning orphaned processes: 1. Add tauri-plugin-single-instance to prevent multiple app instances from running simultaneously. When a second instance is launched, the existing window is focused instead of spawning a new process. 2. Kill the sidecar process on startup timeout before exiting. Previously, if the sidecar failed to start within 7 seconds, the app would exit but leave the spawned sidecar process running as an orphan. This would accumulate orphaned processes each time the app was launched and failed. Root cause: When the sidecar fails to start (e.g., due to module errors), the app would exit without cleaning up, leaving the process running. Repeated launch attempts would spawn more orphaned processes. --- packages/desktop/src-tauri/Cargo.toml | 1 + packages/desktop/src-tauri/src/lib.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/packages/desktop/src-tauri/Cargo.toml b/packages/desktop/src-tauri/Cargo.toml index b7c238f064f..9ca5880c029 100644 --- a/packages/desktop/src-tauri/Cargo.toml +++ b/packages/desktop/src-tauri/Cargo.toml @@ -29,6 +29,7 @@ tauri-plugin-window-state = "2" tauri-plugin-clipboard-manager = "2" tauri-plugin-http = "2" tauri-plugin-notification = "2" +tauri-plugin-single-instance = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/packages/desktop/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs index 46c0ab256db..cbca27a0a49 100644 --- a/packages/desktop/src-tauri/src/lib.rs +++ b/packages/desktop/src-tauri/src/lib.rs @@ -189,6 +189,16 @@ pub fn run() { let updater_enabled = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some(); let mut builder = tauri::Builder::default() + .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { + // When a second instance is launched, focus the existing window instead + if let Some(window) = app.get_webview_window("main") { + let _ = window.set_focus(); + #[cfg(target_os = "windows")] + { + let _ = window.unminimize(); + } + } + })) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_window_state::Builder::new().build()) .plugin(tauri_plugin_store::Builder::new().build()) @@ -222,6 +232,10 @@ pub fn run() { let timestamp = Instant::now(); loop { if timestamp.elapsed() > Duration::from_secs(7) { + // Kill the sidecar before showing dialog to prevent orphaned processes + let _ = child.kill(); + println!("Killed sidecar due to startup timeout"); + let res = app.dialog() .message("Failed to spawn OpenCode Server. Copy logs using the button below and send them to the team for assistance.") .title("Startup Failed")