Fix ACP connection and thread leak (#35670)

When you switched away from an ACP thread, the `AcpThreadView` entity
(and thus thread, and subprocess) was leaked. This happened because we
were using `cx.processor` for the `list` state callback, which uses a
strong reference.

This PR changes the callback so that it holds a weak reference, and adds
some tests and assertions at various levels to make sure we don't
reintroduce the leak in the future.

Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga 2025-08-05 19:10:51 -03:00 committed by GitHub
parent f27dc7dec7
commit b7469f5bc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 73 additions and 27 deletions

View file

@ -19,7 +19,6 @@ pub struct AcpConnection {
sessions: Rc<RefCell<HashMap<acp::SessionId, AcpSession>>>,
auth_methods: Vec<acp::AuthMethod>,
_io_task: Task<Result<()>>,
_child: smol::process::Child,
}
pub struct AcpSession {
@ -47,6 +46,7 @@ impl AcpConnection {
let stdout = child.stdout.take().expect("Failed to take stdout");
let stdin = child.stdin.take().expect("Failed to take stdin");
log::trace!("Spawned (pid: {})", child.id());
let sessions = Rc::new(RefCell::new(HashMap::default()));
@ -61,7 +61,11 @@ impl AcpConnection {
}
});
let io_task = cx.background_spawn(io_task);
let io_task = cx.background_spawn(async move {
io_task.await?;
drop(child);
Ok(())
});
let response = connection
.initialize(acp::InitializeRequest {
@ -84,7 +88,6 @@ impl AcpConnection {
connection: connection.into(),
server_name,
sessions,
_child: child,
_io_task: io_task,
})
}
@ -155,8 +158,10 @@ impl AgentConnection for AcpConnection {
fn prompt(&self, params: acp::PromptRequest, cx: &mut App) -> Task<Result<()>> {
let conn = self.connection.clone();
cx.foreground_executor()
.spawn(async move { Ok(conn.prompt(params).await?) })
cx.foreground_executor().spawn(async move {
conn.prompt(params).await?;
Ok(())
})
}
fn cancel(&self, session_id: &acp::SessionId, cx: &mut App) {