a cancelled call does not leave its conn for the next one (V-638)

The watchdog and the end of the call race by construction: a cancellation
landing as the reply arrives closes a conn the call had already finished
with, and c.conn still pointed at the closed socket.

It was survivable before this. A write to a closed socket is
errWriteLost, which re-dials and retries, and that retry is safe because
nothing was sent. So this buys one round trip, not a correctness fix, and
the new test says so rather than pretending to catch a break.
This commit is contained in:
2026-08-06 23:09:05 +04:00
parent bd53372616
commit 9cdec11346
2 changed files with 33 additions and 1 deletions
+11 -1
View File
@@ -255,8 +255,18 @@ func (c *Client) roundtrip(ctx context.Context, m Method, raw json.RawMessage, r
}
defer conn.SetDeadline(time.Time{})
// The watchdog and the end of the call race by construction: a cancellation
// landing just as the reply arrives can close a conn this call is already
// done with, and c.conn would still point at the closed socket. So a call
// whose context ended does not leave the conn behind for the next one,
// whichever of the two got there first.
done := make(chan struct{})
defer close(done)
defer func() {
close(done)
if ctx.Err() != nil {
c.drop()
}
}()
go func() {
select {
case <-ctx.Done():