Skip to content

Fix Windows AppHost cleanup job routing - #20494

Merged
David Negstad (danegsta) merged 3 commits into
mainfrom
danegsta-investigate-session-container-shutdown
Sep 26, 2026
Merged

David Negstad (danegsta) merged 3 commits into
mainfrom
danegsta-investigate-session-container-shutdown

Conversation

@danegsta

@danegsta David Negstad (danegsta) commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Description

On Windows, session-scoped containers could survive AppHost shutdown because DCP was terminated before it finished cleanup. When a .NET AppHost runs through dotnet run, DCP inherits both the Aspire CLI's outer kill-on-close job and .NET ProcessReaper's inner non-breakaway job. DCP cannot escape that nested job chain, so closing the CLI job kills it during cleanup.

This change omits the Aspire CLI kill-on-close job only for dotnet run and dotnet watch fallback paths. Those paths retain console isolation and cooperative CLI orphan detection. Direct .NET launches still use the CLI job because they do not introduce ProcessReaper, and TypeScript/polyglot AppHost server and guest processes retain their existing job protection.

Focused CLI tests assert the job selection for .NET fallback and direct launches and verify that TypeScript/polyglot server protection remains enabled.

User-facing behavior

Existing shutdown flows such as Ctrl+C and aspire stop can now allow DCP to finish removing session-scoped resources for .NET AppHosts on Windows. Persistent resources remain unaffected, and no new command-line options are required.

Validation

  • Reproduced the original C# scenario and verified normal shutdown removes both session-scoped containers while preserving the persistent PostgreSQL container.
  • Force-terminated the detached CLI and verified parent-liveness detection stops the AppHost while DCP completes session cleanup.
  • Verified a TypeScript AppHost removes its session-scoped container with both existing kill-on-close protections enabled.
  • Ran the focused Aspire CLI tests after removing the synthetic process probe: 181 passed and 3 platform-skipped.

Fixes #20495

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
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Co-authored-by: Copilot App <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 -- 20494

Or

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

@github-actions

This comment has been minimized.

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.

Copilot review overview

🟢 Approval recommended

The launch-mode routing is consistent with the documented Windows job behavior and has focused regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes Windows AppHost cleanup by avoiding the incompatible outer kill-on-close job for dotnet run and dotnet watch, while retaining protection for direct launches.

Changes:

  • Adjusts job routing based on launch mode.
  • Documents the nested-job constraint.
  • Adds focused routing and Windows process-topology tests.
File Description
src/​Aspire.Cli/​Projects/​DotNetAppHostProject.cs Selects parent-exit protection by launch path.
src/​Aspire.Cli/​Processes/​WindowsConsoleProcessJob.cs Documents nested-job breakaway behavior.
tests/​Aspire.Cli.Tests/​Projects/​DotNetAppHostProjectTests.cs Verifies fallback and direct-launch routing.
tests/​Aspire.Cli.Tests/​Projects/​AppHostServerSessionTests.cs Verifies server job protection remains enabled.
tests/​Aspire.Cli.Tests/​Processes/​WindowsConsoleProcessJobTests.cs Tests the real Windows nested-job topology.
tests/​Aspire.Cli.Tests/​TestServices/​ProcessTestHelpers.cs Adds process and file-handshake helpers.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

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.

Copilot review overview

🟡 Changes recommended

The regression probe does not emulate DCP’s breakaway operation, so it can pass without exercising the reported nested-job incompatibility.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

Comment thread tests/Aspire.Cli.Tests/Processes/WindowsConsoleProcessJobTests.cs Outdated
The synthetic child never attempted DCP's breakaway behavior and tested ordinary job inheritance rather than the Aspire routing fix.

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

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.

Copilot review overview

🟢 Approval recommended

The launch-path distinction is correctly scoped and covered by focused tests.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Avoid coupling process cleanup assertions to a transient AppHost that the preceding test deletes while discovery refreshes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This was referenced Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session-scoped containers survive .NET AppHost shutdown on Windows

3 participants