Fix daemon shutdown hang and concurrent-send race

- daemon_net: close the client transport on context cancellation so the
  per-connection Recv loop unblocks; otherwise wg.Wait() in the accept loop
  hung on a still-connected client and the daemon never stopped.
- protocol: guard ConnTransport.Send with a mutex so the subscriber pump and
  command handlers can push frames concurrently without racing the bufio.Writer.

Fixes TestDaemonDetachReattachPreservesProcess (now passes under -race).
This commit is contained in:
2026-05-27 13:59:47 +01:00
parent d07a09d64f
commit 95b1967e9b
2 changed files with 16 additions and 1 deletions

View File

@@ -232,6 +232,14 @@ func handleDaemonAttach(ctx context.Context, registry *ProjectRegistry, t protoc
_ = sendSnapshot(t, project, view.FocusedID)
}
// Close the transport when the daemon context is cancelled (shutdown or
// `daemon stop`). Without this the t.Recv() loop below blocks forever on a
// still-connected client and the accept loop's wg.Wait() never returns.
go func() {
<-ctx.Done()
_ = t.Close()
}()
done := make(chan struct{})
go func() {
defer close(done)