Skip to content

Fix flaky RemoteHost StartupExit test: avoid crash dumps for expected test-server failures - #21497

Merged
Mitch Denny (mitchdenny) merged 1 commit into
mainfrom
aspireagent/fix-remotehost-startupexit-crashdump
Nov 5, 2026
Merged

Mitch Denny (mitchdenny) merged 1 commit into
mainfrom
aspireagent/fix-remotehost-startupexit-crashdump

Conversation

@davidfowl

Copy link
Copy Markdown
Collaborator

Description

Fixes the intermittent IntegrationHostProcessTests.StartupExit_FailsPromptlyAndPreservesRuntimeDiagnostics timeout in Aspire.Hosting.RemoteHost.Tests. No issue tracks it.

Flake evidence (first attempts, ci.yml, Oct 16–30)

  • PR runs: 1,086 total, 503 of which were rerun. Attempt-1 failed-test names were parsed from 2,245 failed jobs.
    • This test failed attempt 1 on 4 / 503 rerun runs, each on a different, unrelated branch.
    • In each case the same job on the same head passed on rerun (confirmed via check-runs for 3 of the 4 heads).
  • main: 0 / 128 runs.
Date Branch OS Job createdump time
Oct 19 codex/persistent-dashboard ubuntu 118356484862 10.7s
Oct 20 darc-main-bddce1ed… ubuntu 118451125990 9.7s
Oct 21 davidfowl/lean-native-runtime-feasibility windows 119032099641 16.3s
Oct 28 dependabot/github_actions/github-actions-ebbe822166 windows 122964740478 16.4s

Root cause

The fixture's generated test server (IntegrationHostProcessFixture.HostProgram) lets expected server failures escape Program.Main as unhandled exceptions. This includes startup failure, missing command, startup deadline, crash-loop and changed signature, which come from host.RunAsync() or IntegrationHostLauncher.ThrowIfFailed().

On CI the test platform runs with --crashdump. The DOTNET_DbgEnableMiniDump* settings are inherited by the child test server, so every expected failure crashes the runtime and writes a full dump before the process exits. Each failing log shows the sequence:

Unhandled exception. System.InvalidOperationException: Integration host supervisor for 'lifetime-test' ... exited with code 23.
[createdump] Dump successfully written in 16311ms
failed ...StartupExit_FailsPromptlyAndPreservesRuntimeDiagnostics (16s 896ms)
  System.TimeoutException : The operation has timed out.

StartupExit waits only server.Exit.WaitAsync(15s), so whenever dump writing took about 10–16s the test timed out. The other failure-path tests use 30s deadlines but pay the same cost, and every one of them leaves a 250–300MB dump.

Fix (test infrastructure only)

  • The generated host now catches the failure, writes it to stderr (unwrapping TargetInvocationException from the reflected ThrowIfFailed), and sets the dedicated Environment.ExitCode = 87. All diagnostics the tests assert on are kept, including exited with code 23 and the recovery messages.
  • The failure-path tests (StartupExit, MissingCommand, StartupDeadline ×2, CrashLoop, ChangedSignature) now assert Assert.Equal(HostFailureExitCode, server.ExitCode) instead of NotEqual(0), or in addition to the existing checks for StartupExit. This assertion is stricter and is the regression check: it fails while the server crashes. On Linux a crashed server exits with 134 (SIGABRT).

No product code changes. No timeouts were changed, and no sleeps or retries were added.

Before/after (local, Linux)

Run with --filter-class *IntegrationHostProcessTests and crash dumps enabled (DOTNET_DbgEnableMiniDump=1), as on CI:

Result Crash dumps written
Before (old host program, new assertions) 6 failed / 9 passed. Every failure-path test: Expected: 87, Actual: 134 7
After 15 / 15 passed 0

The full Aspire.Hosting.RemoteHost.Tests suite passes after the fix: 686 passed, 0 failed, 5 skipped.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No

🤖 Posted by AspireAgent (AI Agent)

The IntegrationHostProcessTests fixture's generated test server let expected
startup/recovery failures escape Program.Main as unhandled exceptions. On CI the
test platform's --crashdump settings are inherited by child processes, so each
expected failure wrote a full crash dump (9.7-16.3s) before the process exited,
exceeding StartupExit's 15s exit deadline.

Handle the failure in the generated host, write it to stderr, and exit with a
dedicated code (87). Failure-path tests now assert that exact exit code instead
of NotEqual(0), which fails (134) while the server still crashes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 21497

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 21497"

@aspire-repo-bot
aspire-repo-bot Bot requested a balanced review from Copilot October 30, 2026 20:47
@github-actions github-actions Bot added the area-integrations Issues pertaining to Aspire Integrations packages label Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Tests selector

1 / 100 PR test projects · 0 PR jobs, from 2 changed files.

Selected PR test projects (1 / 100)

Aspire.Hosting.RemoteHost.Tests

Selected PR jobs (0)

none


How these were chosen — grouped by what changed

🧪 tests/Aspire.Hosting.RemoteHost.Tests/IntegrationHostProcessTests.cs (changed test)
→ 1 directly: Aspire.Hosting.RemoteHost.Tests

🧪 tests/Aspire.Hosting.RemoteHost.Tests/TestServices/IntegrationHostProcessFixture.cs (changed test)
→ 1 directly: Aspire.Hosting.RemoteHost.Tests

Job reasons

none


Selection computed for commit 404e03e.

Copilot AI 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.

🟢 Approval recommended

No active review issues remain for the test-infrastructure changes.

No open issues 🎉

What changed in this PR

This PR addresses a flaky RemoteHost process test by handling expected test-server failures without triggering runtime crash dumps. Changes are limited to test infrastructure; product code and timeouts remain unchanged.

Changes:

  • Catch server failures, preserve exception diagnostics on stderr, and exit with code 87.
  • Strengthen failure-path tests to require the handled-failure exit code rather than any nonzero exit.
File Description
tests/​Aspire.Hosting.RemoteHost.Tests/​TestServices/​IntegrationHostProcessFixture.cs Handles server exceptions and defines the dedicated failure exit code.
tests/​Aspire.Hosting.RemoteHost.Tests/​IntegrationHostProcessTests.cs Asserts the dedicated exit code across expected failure scenarios.

Review effort: Balanced

@davidfowl
David Fowler (davidfowl) marked this pull request as ready for review October 30, 2026 21:17

Copy link
Copy Markdown
Collaborator Author

Related flake covered by this PR: IntegrationHostProcessTests.CrashLoop_StopsTheSessionAfterThreeRestartAttempts

I vetted this test from the same PR-rerun scan: ci.yml PR runs from Oct 16–30, where 503 runs had a rerun. It failed on attempt 1 in 3 of those runs.

  • Two hits have the same root cause as this PR. The hits are on Linux at be18c21 (job 118356484862) and c36e445 (job 118451125990).
    • Each failure is a TimeoutException at the test's 30s server.Exit.WaitAsync.
    • The restarts and the "failed after 3 restart attempts" log happen within about 0.3s.
    • Then the "Integration host recovery failed" exception escapes the generated host's Main, and createdump writes a 450 MB dump. On a runner at 99% CPU, that took 10.6s.
    • With this PR's fixture change, the server catches that exception and exits with code 87, so no dump is written. The test now asserts that exit code.
    • Both runs passed on rerun of the same head.
  • One hit has a different cause, and this PR does not address it. The hit is on Windows at 5ec6039 (job 123711630335).
    • ChildProcess.DisposeAsync threw an IOException because the supervisor's exit-code file was "being used by another process".
    • That cleanup failure ended supervision, so the host never restarted.
    • So far this is the only occurrence among the 14 failed Windows RemoteHost jobs, so I'm tracking it separately and not changing it here.

🤖 Posted by AspireAgent (AI Agent)

@mitchdenny
Mitch Denny (mitchdenny) merged commit de0bdf1 into main Nov 5, 2026
59 checks passed
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 17.0 milestone Nov 5, 2026
@aspire-repo-bot

Copy link
Copy Markdown
Contributor

✅ No documentation update needed.

docs_optional → test_only

Triggered signals (1): pr_body_has_cli_flag_mention. Evidence: the PR body mentions the test platform's --crashdump flag, which is test-infrastructure context, not an Aspire user-facing flag. Both changed files match tests/Aspire.Hosting.RemoteHost.Tests/**, and only_test_or_build_changes is true. The signal is a false positive and no user-facing change exists.

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

Labels

area-integrations Issues pertaining to Aspire Integrations packages flaky-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants