feat: fix orphaned OpenCode processes cleanup on restart or exit
This commit is contained in:
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Desktop: fixed orphaned OpenCode processes not being cleaned up on restart or exit.
|
||||
|
||||
|
||||
## [1.5.0] - 2026-01-16
|
||||
|
||||
- UI: added a new Files tab to browse workspace files directly from the interface.
|
||||
|
||||
Generated
+1
-1
@@ -2977,7 +2977,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openchamber-desktop"
|
||||
version = "1.4.9"
|
||||
version = "1.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
||||
@@ -451,13 +451,20 @@ impl OpenCodeManager {
|
||||
}
|
||||
|
||||
async fn graceful_stop(&self) -> Result<()> {
|
||||
let port_to_kill = self.current_port();
|
||||
|
||||
let mut guard = self.child.lock().await;
|
||||
let Some(mut child) = guard.take() else {
|
||||
// No child, but still kill by port in case of orphaned processes
|
||||
drop(guard);
|
||||
kill_process_on_port(port_to_kill);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if child.try_wait()?.is_some() {
|
||||
// Already exited
|
||||
// Already exited, but still clean up by port
|
||||
drop(guard);
|
||||
kill_process_on_port(port_to_kill);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -482,6 +489,8 @@ impl OpenCodeManager {
|
||||
match timeout(Duration::from_secs(3), child.wait()).await {
|
||||
Ok(_) => {
|
||||
info!("[desktop:opencode] exited gracefully");
|
||||
drop(guard);
|
||||
kill_process_on_port(port_to_kill);
|
||||
return Ok(());
|
||||
}
|
||||
Err(_) => {
|
||||
@@ -501,10 +510,28 @@ impl OpenCodeManager {
|
||||
}
|
||||
}
|
||||
|
||||
drop(guard);
|
||||
kill_process_on_port(port_to_kill);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn kill_process_on_port(port: Option<u16>) {
|
||||
let Some(port) = port else { return };
|
||||
|
||||
// Kill any process listening on our port to clean up orphaned children.
|
||||
// The opencode CLI is a Node wrapper that spawns the actual binary as a child.
|
||||
// Killing the wrapper doesn't kill the child, so we kill by port.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::process::Command;
|
||||
let _ = Command::new("sh")
|
||||
.args(["-c", &format!("lsof -ti:{} | xargs kill -9 2>/dev/null || true", port)])
|
||||
.output();
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if CLI binary exists (can be called dynamically for polling)
|
||||
pub fn check_cli_exists() -> bool {
|
||||
if std::env::var("OPENCHAMBER_DISABLE_CLI").is_ok() {
|
||||
|
||||
Reference in New Issue
Block a user