From 5a7a2a89c32ce8797440604ef43df04eec62e5e1 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 21 Apr 2026 19:27:17 -0700 Subject: [PATCH] app-server-client: tolerate remote shutdown race --- codex-rs/app-server-client/src/remote.rs | 29 ++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/codex-rs/app-server-client/src/remote.rs b/codex-rs/app-server-client/src/remote.rs index 51015f8e7b34..c8e9a93d2e69 100644 --- a/codex-rs/app-server-client/src/remote.rs +++ b/codex-rs/app-server-client/src/remote.rs @@ -612,14 +612,9 @@ impl RemoteAppServerClient { .send(RemoteClientCommand::Shutdown { response_tx }) .await .is_ok() - && let Ok(command_result) = timeout(SHUTDOWN_TIMEOUT, response_rx).await + && let Ok(Ok(close_result)) = timeout(SHUTDOWN_TIMEOUT, response_rx).await { - command_result.map_err(|_| { - IoError::new( - ErrorKind::BrokenPipe, - "remote app-server shutdown channel is closed", - ) - })??; + close_result?; } if let Err(_elapsed) = timeout(SHUTDOWN_TIMEOUT, &mut worker_handle).await { @@ -981,4 +976,24 @@ mod tests { skipped: 1 })); } + + #[tokio::test] + async fn shutdown_tolerates_worker_exit_after_command_is_queued() { + let (command_tx, mut command_rx) = mpsc::channel(1); + let (_event_tx, event_rx) = mpsc::channel(1); + let worker_handle = tokio::spawn(async move { + let _ = command_rx.recv().await; + }); + let client = RemoteAppServerClient { + command_tx, + event_rx, + pending_events: VecDeque::new(), + worker_handle, + }; + + client + .shutdown() + .await + .expect("shutdown should complete when worker exits first"); + } }