Never match responses on a connection whose write failed mid-flight (#2919) (#3205)
A write that dies after its message has been queued in _writtenAwaitingResponse must either complete, or take the connection out of service. Otherwise the queue is permanently one message out of step with the replies on the wire, and every caller on that connection silently receives somebody else's answer. Both recovery paths allocate before they reach RecordConnectionFailed: message.Fail goes via ResultProcessor.ConnectionFail (StringBuilder plus message.ToString()), and HandleWriteException builds a RedisConnectionException. That code only ever runs *because* something already failed, so under memory exhaustion it fails again and teardown is skipped. v3 adding the second teardown attempt in HandleWriteException narrowed this from two faults to three; it did not close it. So make the decision to stop trusting the connection allocation-free, infallible, and first: - PhysicalConnection.PoisonWrite sets a volatile bool, nothing more - both write-failure catches call it before anything that can allocate - MatchNextResult refuses to match once poisoned, throwing a pre-allocated sentinel so the read loop runs the normal teardown and fails everything queued - the write path refuses to queue onto a poisoned connection Worst case this degrades to timeouts, which is the right trade against handing back silently wrong data. Adds a regression test, plus the internal seam it needs to simulate a teardown that cannot allocate. On the previous code that test fails with GET k0 returning v1 - the exact symptom reported in #2919.
M
Marc Gravell committed
e27e9e1e8c0c19c79bc892679cfaf6cf36c975a5
Parent: d37414d
Committed by GitHub <noreply@github.com>
on 9/6/2026, 5:39:28 PM