Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Fix Dispose and SendData Race on Http3 Test by liveans · Pull Request #91291 · dotnet/runtime · GitHub
Skip to content

Fix Dispose and SendData Race on Http3 Test - #91291

Merged
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync
Sep 5, 2023
Merged

Fix Dispose and SendData Race on Http3 Test#91291
liveans merged 2 commits into
dotnet:mainfrom
liveans:http3_server_client_tasks_sync

Conversation

@liveans

@liveansliveans commented Aug 29, 2023

Copy link
Copy Markdown
Contributor

Fixes#87552

When the server task was completed, the stream was getting disposed of before the sent data arrived. So with this fix, we're waiting until the client task is completed on the server task before we complete the server task.

@ghostghost assigned liveansAug 29, 2023
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #87552

When the task was completed, the stream was getting disposed of before the sent data arrived. So, we're waiting until clientTask is completed on the server task before we complete the server task.

Author:liveans
Assignees:-
Labels:

area-System.Net.Http

Milestone:-

@liveans
liveans marked this pull request as ready for review August 29, 2023 19:38
@liveans
liveans requested a review from a teamAugust 29, 2023 19:39
await requestStream.ReadRequestDataAsync();
await requestStream.SendResponseAsync(isFinal: false);
await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") });
await semaphore.WaitAsync();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can get stuck here forever if the client side fails for whatever reason. It may be find for the test. But that makes me wonder if we can simply move declaration of the connection above the task and perhaps keeping it alive by checking some properties after the client request is finished.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we won't stuck because, at the end of the test, we're awaiting them with timeout. We can also try something else to do it, but this pattern is commonly used in this test suite.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

@liveansliveansAug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think I can also add a timeout to this WaitAsync as well, in that case. Thanks for pointing to this!

@rzikmrzikmAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the test fail but the server Task would still be blocked, right?

If the await gets never completed, wouldn't the async state machine get GC collected anyway, since nothing is rooting it?

If the test is going to fail without ever releasing the semaphore, then all references to the test async state machine get dropped, and the call to WaitAsync is not rooting the semaphore itself in any static field anywhere. So I don't think adding timeout is necessary.

@MihaZupanMihaZupanAug 31, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A WaitAsync Task with a timeout will root itself.
The Timer it creates internally has a reference to the Task, while also being rooted in a static field (the list of all timers).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But a WaitAsync on SemaphoreSlim without timeout won't root the state machine, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WaitAsync by itself won't, but if you're waiting on a SemaphoreSlim without a timeout, the expectation is that something else is going to signal you to continue eventually (or you're stuck regardless).

The Task returned by WaitAsync is stored in a linked list of waiters inside the SemaphoreSlim.
So as long as there is something out there with a reference to the semaphore and rooting it, it is by extension rooting the state machine of the WaitAsync caller.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

@rzikmrzikm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@liveans

liveans commented Aug 30, 2023

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?

It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

@wfurt

Copy link
Copy Markdown
Member

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

@liveans

Copy link
Copy Markdown
ContributorAuthor

I'm wondering if this is only one test with this pattern or if we have more cases like this. And if this is the only one, is there reason why it needs to follow special pattern?
It is good that root cause is understood and it really seems like just test problem.

No this is not the only test, other tests in this test suite are also using the same pattern.

Should we fix them as well? While we may not see many failures at the moment I'm wondering if that is just ticking bomb. It would be nice IMHO to find stable pattern and use it as much as we can to make the test similar when we can - I think that would make investigations and maintenance much easier.

Yes, I think we should also fix them, they have similar symptoms, but I briefly looked at them and didn't find exact same root cause over there. (e.g. One of them has Connection aborted (261)) This SemaphoreSlim pattern is quite common, and as far as I can see, there are no failures on those tests that we use this pattern.

@liveans
liveans merged commit e3925e3 into dotnet:mainSep 5, 2023
@ericstj

Copy link
Copy Markdown
Member

Did you want to backport this test change to 8.0?

@liveans

Copy link
Copy Markdown
ContributorAuthor

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6101643065

@karelzkarelz added this to the 9.0.0 milestone Sep 7, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 7, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Httptest-enhancementImprovements of test source code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test Failure] System.Net.Http.Functional.Tests.HttpClientHandlerTest_Http3.ServerSendsTrailingHeaders_Success

6 participants

@liveans@wfurt@ericstj@karelz@MihaZupan@rzikm