Re-enable Microsoft.Extensions.Hosting shutdown functional coverage in CI and harden shutdown startup/Helix/NET481 compatibility#128252
Conversation
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f2762648-8aaf-44cd-a0bb-269b2a6b371d Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
|
@copilot , the shutdown tests are failing with this error on helix machines: Comments Error message Stack trace |
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb9c1b-1794-4ebc-a563-bec6823fec1c Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
... Fixed in b9cd702. I removed the source-tree lookup and switched the shutdown tests to run TestApp from the deployed test output ( |
|
@copilot , this time it failed with this error: Test Failures (700 tests failed) ❌ Microsoft.AspNetCore.Hosting.FunctionalTests.ShutdownTests.ShutdownTestRun [Console] [Details] [Artifacts] [0.70% failure rate] |
… 180s for stress environments Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Fixed in f9172b4. I've addressed both remaining issues:
|
| if (!process.HasExited) | ||
| { | ||
| process.Kill(); | ||
| // Wait for the process to actually exit after Kill() before accessing ExitCode | ||
| if (!process.WaitForExit(5000)) |
There was a problem hiding this comment.
@copilot, extend the timeout then, something like 30 seconds should be fine as the application is fairly minimal.
| var psi = new ProcessStartInfo | ||
| { | ||
| FileName = "kill", | ||
| Arguments = $"-TERM {processId}", | ||
| RedirectStandardOutput = true, | ||
| RedirectStandardError = true, | ||
| UseShellExecute = false | ||
| }; |
There was a problem hiding this comment.
On .Net 11, you could use Process.GetProcessById(processId).SafeHandle.Signal(PosixSignal.SIGTERM). I think this only runs on Unix on .Net 11, so it could make sense to use that instead.
Or you could use the PInvoke approach from ShutdownTests. Both calls to kill should probably use the same approach.
There was a problem hiding this comment.
Implemented in 16bc033. ProcessExtensions.KillProcessUnix now uses libc kill(pid, SIGTERM) (matching the ShutdownTests signal approach), waits for exit, and falls back to Process.Kill() if graceful termination fails.
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
| await started.Task.WaitAsync(TimeSpan.FromSeconds(180)); | ||
|
|
||
| SendShutdownSignal(deployer.HostProcess); | ||
|
|
There was a problem hiding this comment.
Note
AI-generated.
Fixed in 14a6f4c97. The shutdown test now subscribes before DeployAsync() starts output capture, via SelfHostDeployer.OutputReceived, so the initial Started line can’t be missed.
|
@copilot , I left comments for you, please implement them. |
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Fixed in |
| internal static class ProcessExtensions | ||
| { | ||
| private const int ESRCH = 3; | ||
| private const int SIGTERM = 15; |
There was a problem hiding this comment.
According to Copilot CLI, it is not guaranteed by POSIX standard that number is always 15.
SIGTERM's value of 15 is not mandated by POSIX itself — POSIX only requires the name to exist. However, every known Unix/Linux implementation uses 15, dating back to early System V and BSD. It's a universal de facto standard at this point
In Process we obtain number at runtime using helper:
Have you considered using something similar here?
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
|
@copilot , I left two replies, please implement them |
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Note AI-generated. Implemented in |
main PR
This PR now includes the full follow-up hardening required by CI feedback after re-enabling
Microsoft.Extensions.Hostingfunctional shutdown coverage.Final scope of changes
AppContext.BaseDirectory) instead of source-tree project discovery.PreservePublishedApplicationForDebuggingdependency by using a borrowed published app path that does not delete test output on cleanup.killprocess usage in shutdown signaling withlibcsignal calls for Helix/minimal-image compatibility.SIGINT/SIGTERMnumbers at runtime instead of hard-coding them, matching the runtime's platform-specific signal mapping approach.SIGTERM)Process.Kill()) when neededProcess.Kill()to 30 seconds, reducing false failures when the app has finished shutdown logging but needs a little longer to exit cleanly under load.DeployAsync()starts process output capture, so the initialStartedline cannot be missed.net481compatibility by usingMarshal.GetLastWin32Error().Validation
./build.sh clr+libs -rc releasesucceeds../build.sh clr+libs+host -rc release -lc releasesucceeds.Microsoft.Extensions.Hosting.Functional.Testsbuilds successfully fornet481.dotnet build /t:test Microsoft.Extensions.Hosting.Functional.Tests.csproj -c Release -f net11.0 /p:TestFilter=Microsoft.AspNetCore.Hosting.FunctionalTests.ShutdownTestspasses (2/2).