-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Observe any exception on HTTP connection scavenge. #110982
base: main
Are you sure you want to change the base?
Observe any exception on HTTP connection scavenge. #110982
Conversation
Tagging subscribers to this area: @dotnet/ncl |
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.
Thank you for filing the issue and looking to fix it.
We don't want to unconditionally suppress the error here as it's meaningful for the request.
Instead, we'll have to figure out in what case it's possible that no thread would observe the exception.
It's not immediately obvious to me how that could happen with .NET 9.0.
Do you mind double-checking that you were indeed running on 9.0 and not 8.0?
@@ -267,8 +267,9 @@ async ValueTask<int> ReadAheadWithZeroByteReadAsync() | |||
|
|||
return read; | |||
} | |||
catch (Exception error) when (TransitionToCompletedAndTryOwnCompletion()) | |||
catch (Exception error) |
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.
TransitionToCompletedAndTryOwnCompletion
controls who is responsible for observing the exception.
If a thread has already flipped _readAheadTaskStatus
to CompletionReserved
, it's also responsible for observing any exceptions thrown by this method.
The exact exception is meaningful as the request may fail with it as the inner exception.
If it has not (task status is still Started
), the method itself will observe and suppress the exception. In that case we don't necessarily care that/which exception occured, just that the read completed before a request attempted to use the connection.
Thank you for taking time to review and being so fast in it! I drafted the PR mainly to understand how much I went off road with my interpretation. I'm still trying to create a repro under Functional.Tests but have been unsuccessful so far.
Long shot here: what if CheckUsabilityOnScavenge got an exception while the read-ahead task is CompletionReserved, because PrepareForReuse ran just at the "right" time, and then the connection is disposed? It looks to me nobody may be observing the read-ahead task in this case.
I'm afraid we are: I double checked the content of our self-contained deployed package, and it contains, among the others, System.Net.Http.dll 9.0.24.52809 (2024-10-29) and runtimeconfig.json specifying Microsoft.NETCore.App and Microsoft.AspNetCore.App 9.0.0. |
If runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs Line 123 in 756e620
Either when doing the initial read here runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs Lines 618 to 634 in 756e620
or if an exception occurs here runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs Lines 854 to 859 in 756e620
If there's a case where we could throw between
It is most likely a harmless issue, but we should still track down the root cause. |
Makes sense to me, and confirms my understanding, thanks. What about the code paths that check for a read-ahead task not yet started, though? In my understanding, there could be a case where both runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs Line 162 in 756e620
Of course, apologies if I misunderstood the implementation! |
While not obvious from the methods themselves, for both of those, the caller first removes the connection from the pool such that only 1 thread has access to the connection at any given point, hence why they use non-synchronized checks. Note how both are called after popping the connection from the stack: Lines 441 to 443 in 1613dd3
Lines 37 to 46 in 1613dd3
|
Fixes #110951