-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dispose server connection after client has been disposed #56720
Dispose server connection after client has been disposed #56720
Conversation
Tagging subscribers to this area: @dotnet/ncl Issue DetailsThere is a race condition in Http2Connection in processing of GOAWAY frame between disposing The above behavior can lead to test code gets hang if it calls This PR changes the call order, so Fixes #44183
|
Are you sure about this? |
Sorry, it's my mistake. You are right that it's a completion not disposal.
It's not guaranteed in case of GOAWAY processing because Http2Stream only puts RST_STREAM on the outgoing queue, but doesn't wait for it to be sent. Once it has been put onto, Http2Stream will call In more details, the GOAWAY processing logic is as follows:
|
Thanks for the great summary! The race condition seems to be very general and independent from the UDS transport and Windows. Any ideas why is the failure Windows only and why don't we see it in other tests following a similar pattern? |
I think it has something to do with threads scheduling. There might be a Windows-specific behavior in the thread pool which exposes this race. |
I think |
A couple thoughts: First, I think we have an issue here where we should not be sending RST_STREAM in this case. The OnReset logic is used for receiving both GOAWAY and RST_STREAM. The spec is very clear that when receiving a RST_STREAM, we must not send a RST_STREAM back:
https://httpwg.org/specs/rfc7540.html#StreamErrorHandler
https://httpwg.org/specs/rfc7540.html#RST_STREAM There doesn't seem to be any similar language for GOAWAY, but since we use the same code to handle both it doesn't really matter. I thought we had a test for this -- i.e. that we don't send RST_STREAM after receiving it -- but I can't find it now. If not we should add one. |
Another thought, re this:
FinalTeardown will also complete the writer queue, i.e. call _writeChannel.Writer.Complete. This will eventually cause the write queue to drain. It might be better to defer disposing the underlying stream until the write queue is completely drained. I don't think it should matter, since at this point all requests are completed -- but at the very least it would avoid some unnecessary exceptions. |
@geoffkizer Do you suggest to change that logic now? I'm afraid that it can be too big change for this release phase. |
We should certainly consider it. We are breaking the RFC here. Any server would be within their rights to fail the entire connection when we do this. I don't know how likely that is to happen in practice, but I know we would 100% service this if a customer did hit it. I assume this is a regression from 5.0, right? Do we know how we regressed this? |
Just to clarify, stopping sending RST_STREAM in OnReset won't fix this test because due to some reason it cannot get a zero-byte read on the connection close. If you are asking whether sending RST_STREAM in OnReset is a regression from 5.0, then I don't know currently. Need to check that code. |
@antonfirsov Now, I do agree with you. Since, we discovered that |
Triage: We decided to keep the test disabled for now. |
Submitted #56830 |
There is a race condition in Http2Connection in processing of GOAWAY frame between disposing the client's SslStream (
_stream
field) together with shutting down Http2Connection and sending RST_STREAM for aborted Http2Streams. It could be that a stream put an outgoingRST_STREAM
on_writeChannel.Writer
queue, but then_writeChannle.Writer
has got disposed before sending thatRST_STREAM
frame.The above behavior can lead to test code gets hang if it calls
Http2LoopbackConnection.ShutdownIgnoringErrorsAsync
directly or as part of a Dispose call because this method first sendsGOAWAY
frame to client and then waits for any frame from client which can never arrive due to that race condition.This PR changes the call order, so
Http2LoopbackConnection
is called after the HttpClient has been disposed.Fixes #44183