Skip to content

fix: resolve /exit 5-second delay by properly closing transport writer#72

Merged
yishuiliunian merged 2 commits intomainfrom
fix/fast-exit-transport-close
Apr 3, 2026
Merged

fix: resolve /exit 5-second delay by properly closing transport writer#72
yishuiliunian merged 2 commits intomainfrom
fix/fast-exit-transport-close

Conversation

@yishuiliunian
Copy link
Copy Markdown
Contributor

Summary

  • /exit took ~5s because AgentProcess::shutdown() failed to close stdin (already moved into StdioTransport). The child never received EOF, triggering the 5s grace period + SIGKILL every time.
  • Added Transport::close() trait method with interior mutability — shuts down the writer through any Arc clone, bypassing the ownership problem.
  • Fixed child-side shutdown (forward_loop interrupt + abort), added kill_on_drop(true) to shell commands, and fixed DuplexTransport's shared connected flag.

Changes

  • loopal-ipc: Transport::close() required trait method; implemented for StdioTransport, TcpTransport, DuplexTransport; Connection::close() delegate; DuplexTransport refactored to independent per-side AtomicBool + consistent Release/Acquire ordering + send() error handling
  • loopal-agent-client: AgentProcess::shutdown() uses transport.close() instead of broken drop(child.stdin.take()); grace period 5s→3s
  • loopal-agent-server: forward_loop EOF handler — 2-signal interrupt pattern with abort fallback for clean child-side shutdown
  • loopal-backend: kill_on_drop(true) on all shell commands (exec_command, exec_background, exec_command_streaming)

Test plan

  • 12 new tests: Transport::close() for stdio (4), tcp (3), duplex (4), forward_loop EOF integration (1)
  • bazel test //... — 48/48 pass
  • bazel build //... --config=clippy — zero warnings
  • CI passes

AgentProcess::shutdown() tried drop(self.child.stdin.take()), but stdin
was already moved into StdioTransport during spawn. The transport behind
Arc had multiple references (AgentProcess + Connection), so the writer
was never closed and the child process never received EOF — every exit
waited for the 5s grace period before SIGKILL.

Fix: add Transport::close() with interior mutability to shut down the
writer through any Arc clone. Also fix the child-side shutdown path
(forward_loop EOF handler with 2-signal interrupt + abort fallback),
add kill_on_drop(true) to shell commands to prevent orphan processes,
and give DuplexTransport independent per-side connected flags.
@yishuiliunian yishuiliunian merged commit e48e49a into main Apr 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant