Skip to content

[release/13.4] Fix aspire stop falsely reporting failure on Unix#17623

Merged
davidfowl merged 2 commits into
release/13.4from
backport/pr-17612-to-release/13.4
May 28, 2026
Merged

[release/13.4] Fix aspire stop falsely reporting failure on Unix#17623
davidfowl merged 2 commits into
release/13.4from
backport/pr-17612-to-release/13.4

Conversation

@aspire-repo-bot
Copy link
Copy Markdown
Contributor

@aspire-repo-bot aspire-repo-bot Bot commented May 28, 2026

Backport of #17612 to release/13.4

/cc @danegsta

Customer Impact

Fixes a Unix/Linux aspire stop race condition that could cause us to fail to report a successful stop.

Testing

Validated via smoke tests in a Linux container.

Risk

Low - ultimately our process cleanup strategy doesn't change much, we're just being more careful about what PIDs we're watching/signaling during shutdown

Regression?

Yes, in 13.4

danegsta and others added 2 commits May 28, 2026 20:33
The stop path treated the managing CLI PID as a success condition. On
Unix the CLI process can remain observable (for example as an unreaped
or briefly lingering process) after the AppHost has already stopped, so
aspire stop reported '\u274c Failed to stop apphost.cs' even when shutdown
completed successfully.

Use the AppHost PID as the success condition, and keep the CLI PID as a
shutdown handle that still gets force-killed when present so we never
leave a true zombie CLI running after the AppHost is gone.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The cascade path (signal launcher CLI, let it terminate 'dotnet run',
and rely on that to terminate the AppHost) is racy on Unix: if the
descendant walk inside 'dotnet run' misses the AppHost, the AppHost
is orphaned to PID 1 and HasExited polling can't distinguish a zombie
from a live process, so 'aspire stop' falsely reports failure after
the full SIGTERM + SIGKILL timeout (~40s).

On Unix we now:
* Send SIGTERM directly to the AppHost PID so it shuts down through
  its own IHostApplicationLifetime path. The launcher CLI and dotnet
  run process exit naturally when their child exits.
* Pass killEntireProcessTree:true when force-terminating on Unix. DCP
  is launched in a separate session there, so force-terminating the
  AppHost tree doesn't take DCP with it; DCP detects the parent gone
  and tears down its own children gracefully.

Windows behavior is preserved: we keep cascading through the launcher
CLI to DCP because DCP is an in-tree descendant of the AppHost on
Windows, and a full tree termination would break DCP's orderly
resource cleanup.

Validation in the repo's Linux container (Ubuntu 24.04 ARM64):
* Baseline: 5/25 failures (20%), failures hit the 40s timeout
* CLI-visibility-only fix: 1/25 failures (4%)
* This change: 0/30 failures, stop wall-time 0.7-2.3s

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 28, 2026 20:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@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 -- 17623

Or

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

@github-actions
Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 107 passed, 0 failed, 2 unknown (commit b22542c)

View all recordings
Status Test Recording Job Artifacts
AddPackageInteractiveWhileAppHostRunningDetached Recording #78395726607 Logs
AddPackageWhileAppHostRunningDetached Recording #78395726607 Logs
AgentCommands_AllHelpOutputs_AreCorrect Recording #78395727276 Logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording #78395727276 Logs
AgentInitCommand_MigratesDeprecatedConfig Recording #78395727276 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording #78395725687 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording #78395725687 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording #78395725687 Logs
AllPublishMethodsBuildDockerImages Recording #78395725765 Logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording #78395726521 Logs
AspireAddPackageVersionToDirectoryPackagesProps Recording #78395727019 Logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording #78395725829 Logs
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles Recording #78395726082 Logs
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive Recording #78395726082 Logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording #78395726694 Logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording #78395727019 Logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording #78395727019 Logs
Banner_DisplayedOnFirstRun Recording #78395727087 Logs
Banner_DisplayedWithExplicitFlag Recording #78395727087 Logs
Banner_NotDisplayedWithNoLogoFlag Recording #78395727087 Logs
CertificatesClean_RemovesCertificates Recording #78395726073 Logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording #78395726073 Logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording #78395726073 Logs
ConfigSetGet_CreatesNestedJsonFormat Recording #78395726184 Logs
CreateAndRunAspireStarterProject Recording #78395727007 Logs
CreateAndRunAspireStarterProjectWithBundle Recording #78395726845 Logs
CreateAndRunEmptyAppHostProject Recording #78395727239 Logs
CreateAndRunJavaEmptyAppHostProject Recording #78395726912 Logs
CreateAndRunJsReactProject Recording #78395726822 Logs
CreateAndRunPythonReactProject Recording #78395725851 Logs
CreateAndRunTypeScriptEmptyAppHostProject Recording #78395726158 Logs
CreateAndRunTypeScriptStarterProject Recording #78395726211 Logs
CreateJavaAppHostWithViteApp Recording #78395725754 Logs
CreateTypeScriptAppHostWithViteApp_AllowsGuestAppPackageManagerToDiffer Recording #78395725991 Logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording #78395725991 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording #78395725766 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording #78395725766 Logs
DashboardRunWithOtelTracesReturnsNoTraces Recording #78395725766 Logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording #78395725766 Logs
DeployK8sBasicApiService Recording #78395725860 Logs
DeployK8sWithExternalHelmChart Recording #78395726355 Logs
DeployK8sWithGarnet Recording #78395727169 Logs
DeployK8sWithMongoDB Recording #78395726699 Logs
DeployK8sWithMySql Recording #78395726120 Logs
DeployK8sWithPostgres Recording #78395726572 Logs
DeployK8sWithRabbitMQ Recording #78395725614 Logs
DeployK8sWithRedis Recording #78395725880 Logs
DeployK8sWithSqlServer Recording #78395725998 Logs
DeployK8sWithValkey Recording #78395726640 Logs
DeployTypeScriptAppToKubernetes Recording #78395726153 Logs
DescribeCommandResolvesReplicaNames Recording #78395726089 Logs
DescribeCommandShowsRunningResources Recording #78395726089 Logs
DetachFormatJsonProducesValidJson Recording #78395725863 Logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording #78395725863 Logs
DoPublishAndDeployListStepsWork Recording #78395726945 Logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording #78395726791 Logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording #78395727276 Logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording #78395725699 Logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording #78395725699 Logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording #78395725699 Logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78395725263 Logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording #78395725991 Logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording #78395726184 Logs
GlobalMigration_HandlesMalformedLegacyJson Recording #78395726184 Logs
GlobalMigration_PreservesAllValueTypes Recording #78395726184 Logs
GlobalMigration_SkipsWhenNewConfigExists Recording #78395726184 Logs
GlobalSettings_MigratedFromLegacyFormat Recording #78395726184 Logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78395725263 Logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording #78395725991 Logs
InteractiveCSharpInitCreatesExpectedFiles Recording #78395726186 Logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording #78395725639 Logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording #78395725765 Logs
LatestCliCanStartStableChannelAppHost Recording #78395727007 Logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording #78395727007 Logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording #78395726694 Logs
LogsCommandShowsResourceLogs Recording #78395726232 Logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording #78395726339 Logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording #78395726339 Logs
PsCommandListsRunningAppHost Recording #78395726250 Logs
PsFormatJsonOutputsOnlyJsonToStdout Recording #78395726250 Logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording #78395726997 Logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording #78395726997 Logs
PublishWithDockerComposeServiceCallbackSucceeds Recording #78395726997 Logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording #78395726997 Logs
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries Recording #78395726695 Logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording #78395726695 Logs
RestoreGeneratesSdkFiles Recording #78395725753 Logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording #78395726468 Logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording #78395726468 Logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording #78395725900 Logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording #78395727012 Logs
RunReportsSyntaxErrorsForDotNetAppHost Recording #78395726874 Logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording #78395726874 Logs
SecretCrudOnDotNetAppHost Recording #78395726157 Logs
SecretCrudOnTypeScriptAppHost Recording #78395726106 Logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording #78395727262 Logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording #78395725721 Logs
StartReportsSyntaxErrorsForDotNetAppHost Recording #78395726874 Logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording #78395726874 Logs
StopAllAppHostsFromAppHostDirectory Recording #78395725697 Logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording #78395726240 Logs
StopNonInteractiveSingleAppHost Recording #78395725697 Logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording #78395727158 Logs
StopWithNoRunningAppHostExitsSuccessfully Recording #78395726607 Logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording #78395726468 Logs
UpdateProjectChannelToStable_CSharpEmptyAppHost_PreservesAspireConfigChannel Recording #78395725667 Logs
UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel Recording #78395725667 Logs
UpdateProjectChannelToStable_TypeScriptSingleFileInit_PreservesAspireConfigChannel Recording #78395725667 Logs
UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel Recording #78395725667 Logs

📹 Recordings uploaded automatically from CI run #26600615811

@davidfowl davidfowl merged commit 1e7134f into release/13.4 May 28, 2026
922 of 928 checks passed
@davidfowl davidfowl deleted the backport/pr-17612-to-release/13.4 branch May 28, 2026 22:12
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.4 milestone May 28, 2026
@aspire-repo-bot
Copy link
Copy Markdown
Contributor Author

✅ No documentation update needed.

docs_optional → bug_fix_restores_documented_behavior

No triggered signals (signal_count = 0). This is a Unix race-condition fix for aspire stop falsely reporting failure — the fix restores the already-documented behavior where aspire stop succeeds when the AppHost stops. The changed files are src/Aspire.Cli/Processes/ProcessShutdownService.cs, src/Shared/ProcessSignaler.cs, and a test file — all internal implementation changes with no new flags, options, commands, or public API surface.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants