Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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" + '
Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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('^' + ".*" + ' Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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('^' + ".*" + ' Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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" + ' Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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('^' + ".*" + ' Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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('^' + ".*" + ' Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy
, '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); } })(); })(); Enable runtime-async for SharedFx-only libraries by wtgodbe · Pull Request #66200 · dotnet/aspnetcore · GitHub
Skip to content

Enable runtime-async for SharedFx-only libraries - #66200

Merged
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async
Apr 24, 2026
Merged

Enable runtime-async for SharedFx-only libraries#66200
wtgodbe merged 19 commits into
mainfrom
wtgodbe/runtime-async

Conversation

@wtgodbe

@wtgodbewtgodbe commented Apr 7, 2026

Copy link
Copy Markdown
Member

Cribbing off of dotnet/runtime#125406. Enable runtime-async for net11.0+ projects that ship only in the Shared Framework. We can't enable it for projects that ship both in the SharedFx & as packages, because runtime-async is incompatible w/ wasm, so anyone who tried to use such a package in a wasm project would be broken.

Also enables runtime-async for tests.

The wasm exclusion checks both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to correctly exclude projects that target WebAssembly via RuntimeIdentifier=browser-wasm even when $(TargetOS) is empty.

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Description

Enables the runtime-async compiler feature for net11.0+ projects that ship only in the ASP.NET Core Shared Framework (IsAspNetCoreApp=true, IsPackable!=true) and for compatible test/test-asset projects. Projects that are also shipped as NuGet packages are excluded because runtime-async is incompatible with WebAssembly, which would break wasm consumers.

Wasm exclusion is enforced by checking both $(TargetOS) != browser and !$(RuntimeIdentifier.StartsWith('browser-')) to cover the case where $(TargetOS) is empty but the project targets wasm via RuntimeIdentifier=browser-wasm.

CopilotAI review requested due to automatic review settings April 7, 2026 17:57
@github-actionsgithub-actionsBot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 7, 2026

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables the runtime-async feature for .NET 11+ projects that ship only in the shared framework, and extends the same enablement to compatible test projects while attempting to avoid WebAssembly where it’s incompatible.

Changes:

  • Turn on runtime-async for IsAspNetCoreApp=true projects that are not packable and target net11.0+.
  • Turn on runtime-async for IsTestProject / IsTestAssetProject targeting net11.0+.
  • Add a TargetOS != browser condition intended to avoid wasm scenarios.

Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
Comment threadDirectory.Build.targets Outdated
@wtgodbewtgodbe added area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 7, 2026
<Features>$(Features);runtime-async=on</Features>
</PropertyGroup>

<!-- Also enable runtime async for compatible test projects -->

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 assume that the tests would fail if not for this, right? Otherwise, I'd probably want to run in both modes at least temporarily.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

I think they would, but I'm largely cribbing off of what runtime did: dotnet/runtime#125406

@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 7, 2026 19:20
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

There's now a consistent failure in Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete

Assert.True() Failure
Expected: True
Actual: False

Looking

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

The test relies on GC to finalize HttpConnection objects — it calls GC.Collect() /
GC.WaitForPendingFinalizers() in a loop and expects the "ApplicationNeverCompleted" log to be triggered within 10 attempts
(line 75).

With runtime-async, the async state machine is different — the runtime keeps the async method's state alive differently than
the traditional compiler-generated state machine. This means the HttpConnection may not be eligible for GC as quickly, causing
the test to need more iterations.

The test already allows up to 30 attempts in the loop (line 69) but asserts that it completes in under 10 (line 75). The
Assert.True(logWaitAttempts < 10) is the assertion that fails — it took 67 seconds total (which is ~30 iterations × ~2s each),
meaning the GC never collected the connection at all.

This is a fundamental behavioral change with runtime-async — the async method's continuation is rooted differently, preventing
the HttpConnection from being finalized.

Verdict: This is a real regression caused by runtime-async. The test depends on GC collecting an HttpConnection whose
application Task never completes — runtime-async changes how the async continuation is rooted, keeping the connection alive.

Fix options:

  1. Opt this test out of runtime-async with [RuntimeAsyncMethodGeneration(false)] — but that only affects the test method, not
    the production code whose async behavior changed
  2. Opt the production code out — the Kestrel connection handling code that's keeping the reference alive
  3. Relax the assertion — but if GC never collects it (30 attempts failed), relaxing won't help
  4. Skip the test when runtime-async is enabled

Since this is a GC-finalization test that's fundamentally incompatible with how runtime-async roots async continuations, the
most pragmatic fix is probably to skip/quarantine it for now and file an issue against the runtime-async feature to ensure
this GC behavior is addressed.

@halter73@BrennanConroy think we should skip this one for now?

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with dotnet/runtime#126735 as the linked issue.

CopilotAI commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

@copilot Quarantine Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests.HttpConnectionManagerTests.CriticalErrorLoggedIfApplicationDoesntComplete, with https://github.com/dotnet/runtime/iss...

Done in 84530c9. Added [QuarantinedTest("https://github.com/dotnet/runtime/issues/126735")] to CriticalErrorLoggedIfApplicationDoesntComplete.

wtgodbeand others added 2 commits April 20, 2026 15:32
Add blame-hang diagnostics with 5m per-test timeout to identify which
specific tests hang with runtime-async enabled. Increase pipeline
timeout to 180m to allow the run to complete. Fix script to preserve
post-processing after nonzero test exit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe
wtgodbe requested a review from a team as a code ownerApril 21, 2026 01:16
wtgodbeand others added 3 commits April 20, 2026 22:51
This test hangs indefinitely with runtime-async enabled due to a
runtime bug with async continuation rooting. Without runtime-async
the test fails cleanly via WaitAssert timeout.
See dotnet/runtime#126735
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wtgodbe

Copy link
Copy Markdown
MemberAuthor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

CopilotAI commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

@copilot please update the PR in the following ways - Don't enable runtime-async for test
asset projects. Undo the changes to .azure/pipelines/components-e2e-tests.yml.

Done in fc44762. Removed IsTestAssetProject from the runtime-async condition (now only IsTestProject enables it) and reverted .azure/pipelines/components-e2e-tests.yml to its state before the blame-hang changes.

@wtgodbe

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0-preview4

@wtgodbe
wtgodbe merged commit f676e0f into mainApr 24, 2026
25 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/runtime-async branch April 24, 2026 00:42
@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0-preview4 (link to workflow run)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-infrastructureIncludes: MSBuild projects/targets, build scripts, CI, Installers and shared framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@wtgodbe@halter73@BrennanConroy