-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Remove SocketException usage #38094
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
Remove SocketException usage #38094
Conversation
src/Servers/Kestrel/Transport.Sockets/src/Internal/TransferResult.cs
Outdated
Show resolved
Hide resolved
|
This needs to be opt in with an API if we do it. Then we can debate if it's on or off by default. |
src/Servers/Kestrel/Transport.Sockets/src/Internal/TransferResult.cs
Outdated
Show resolved
Hide resolved
src/Servers/Kestrel/Transport.Sockets/src/Internal/TransferResult.cs
Outdated
Show resolved
Hide resolved
|
|
||
| namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal | ||
| { | ||
| internal readonly struct TransferResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should just be a ValueTuple
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a base class or as-is? I wouldn't like to see the ValueTuple<> name everywhere it's used, not readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does "Maybe" mean "please change" ?
| if (IsConnectionAbortError(result.SocketError!.SocketErrorCode)) | ||
| { | ||
| // This exception should always be ignored because _shutdownReason should be set. | ||
| error = result.SocketError!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this effectively treating socket errors that aren't considered either aborts or resets as "normal" completions? We definitely should throw for any socket error that we don't recognize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely should throw for any socket error that we don't recognize
It's still throwing the same exceptions outside of this component. This PR only removes any exceptions that were caught (expected) and not re-thrown.
|
If we wanted to go further we don't even need to complete the Input pipe with an error. We could create a new transport feature that exposes the error that can be checked after "normal" completion. We'd only need to throw when app code is in the middle of reading a request body. Otherwise, we can handle the error without ever throwing or catching an exception. I talked to @davidfowl about this a while back, but he didn't like the idea of a non-throwing transport because it would be hard to use. Maybe this would be acceptable if the feature gave a way to opt in to this behavior though. |
src/Servers/Kestrel/Transport.Sockets/src/Internal/SocketOperationResult.cs
Outdated
Show resolved
Hide resolved
|
6 runs, take only 2 fastest.
|
|
Seems like mostly good numbers. The heap fragmentation one is a bit odd |
|
This test failed twice: Microsoft.AspNetCore.Server.IIS.FunctionalTests.Http2TrailerResetTests.Reset_DuringRequestBody_Resets I don't remember it was failing before I merged main. Maybe I made a mistake, will check. |
|
Did we address the breaking change somehow? |
I don't believe there is any breaking change. Please let me know which one I am missing. |
|
This still completes the pipes with exceptions, so we don't need to make a breaking change. My suggestion was to not even throw from the Pipe read by the application. That'd probably be an improvement, but I don't think that's necessary. This still removes half of the throwing and catching in many cases. |
| return false; | ||
| } | ||
|
|
||
| return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should never return true without setting error to some non-null value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I misread this initially. If result.HasError, we should always be returning false. And this should never return false without setting error to some non-null value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are now ignoring "unknown" errors. There are no tests for this, because these errors are unknown and we don't know how to reproduce it, but we definitely should not be swallowing these.
Assuming result.BytesTransferred is 0 given an unkown error (which seems like a safe bet), then the error will get logged as a FIN which is terrible for debugging. If result.BytesTransferred is somehow non-zero, it'd be even worse.
| return true; | |
| // This is unexpected. | |
| error = result.SocketError; | |
| SocketsLog.ConnectionError(_logger, this, error); | |
| return false; |
|
|
||
| break; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we've gotten to this point and transferResult.HasError, we should be doing unexpectedError = shutdownReason = transferResult.SocketError.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did the change, but I don't think it was the behavior before.
|
Sounds like a great improvement. Are we taking this? |
|
All is green, any takers to approve it? |
adityamandaleeka
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. The one thing I'd add is a comment somewhere (maybe in SocketOperationResult) that explains why this is being done. Otherwise, someone could come along later and undo this 😄.
For review only. Not sure which benchmark would be impacted. It appears clearly in connection close, but there are other bottlenecks in this benchmark that make the change insignificant.