Skip to content

Display "Stopping Aspire..." immediately on CTRL+C#17652

Open
JamesNK wants to merge 1 commit into
mainfrom
jamesnk/cancellation-stopping-message
Open

Display "Stopping Aspire..." immediately on CTRL+C#17652
JamesNK wants to merge 1 commit into
mainfrom
jamesnk/cancellation-stopping-message

Conversation

@JamesNK
Copy link
Copy Markdown
Member

@JamesNK JamesNK commented May 29, 2026

Summary

When the user presses CTRL+C, the CLI now displays "Stopping Aspire..." after a short 200ms delay if the command handler hasn't completed yet. This gives immediate user feedback that shutdown is in progress.

Changes

Core feature

  • BaseCommand: Moved cancellation/termination handling from Program.Main into the SetAction lambda. Uses a Task.WhenAny loop with a 200ms TaskCompletionSource timer to show the stopping message if the handler is still running after cancellation.
  • ConsoleCancellationManager: Changed SetStartedHandler to accept Task instead of Task<int> since BaseCommand now manages the exit code directly.
  • CommandResult.FromExitCode: Maps CliExitCodes.Cancelled to CommandResult.Cancelled(exitCode).

Refactoring

  • CommonCommandServices: New class that consolidates the 5+ dependencies previously passed individually to every command constructor (IFeatures, ICliUpdateNotifier, CliExecutionContext, IInteractionService, AspireCliTelemetry, ConsoleCancellationManager, ILoggerFactory). All commands now take a single CommonCommandServices parameter.
  • CliStartupContext: Added CancellationManager property so it flows through DI.
  • Program.cs: Simplified the invoke path — no longer does WhenAny at the top level since BaseCommand handles it.

Test fixes

  • Added using to all BuildServiceProvider() calls in CLI tests to fix FileLoggerProvider holding file handles.
  • Added ConsoleCancellationManager registration to test DI setup.
  • Two new tests for the stopping message behavior (displayed after delay, not displayed if handler completes quickly).
  • Replaced Task.Delay(Timeout.Infinite, ct) with AsyncTestHelpers.WaitForCancellationAsync(ct) for cleaner test code.

Testing

All 3829 CLI tests pass (0 failures, 21 skipped).

- Introduce CommonCommandServices to consolidate BaseCommand dependencies
- Move cancellation/termination handling from Program.Main into BaseCommand
- Show 'Stopping Aspire...' after 200ms if handler hasn't completed post-cancellation
- Add CancellationManager to CliStartupContext and DI container
- Map CliExitCodes.Cancelled in CommandResult.FromExitCode
- Change ConsoleCancellationManager.SetStartedHandler to accept Task (not Task<int>)
- Add BaseCommand tests for cancellation message timing
- Add 'using' to BuildServiceProvider() calls in CLI tests to fix file handle leaks
Copilot AI review requested due to automatic review settings May 29, 2026 07:14
@JamesNK JamesNK added this to the 13.5 milestone May 29, 2026
@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 -- 17652

Or

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

@JamesNK
Copy link
Copy Markdown
Member Author

JamesNK commented May 29, 2026

Too big/risky for 13.4.

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

CLI E2E Tests unknown — 108 passed, 0 failed, 2 unknown (commit a4ef058)

View all recordings
Status Test Recording Job Artifacts
AddPackageInteractiveWhileAppHostRunningDetached Recording #78457263180 Logs
AddPackageWhileAppHostRunningDetached Recording #78457263180 Logs
AgentCommands_AllHelpOutputs_AreCorrect Recording #78457262909 Logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording #78457262909 Logs
AgentInitCommand_MigratesDeprecatedConfig Recording #78457262909 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording #78457263569 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording #78457263569 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording #78457263569 Logs
AllPublishMethodsBuildDockerImages Recording #78457263670 Logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording #78457263205 Logs
AspireAddPackageVersionToDirectoryPackagesProps Recording #78457263565 Logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording #78457263514 Logs
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles Recording #78457262995 Logs
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive Recording #78457262995 Logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording #78457263028 Logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording #78457263565 Logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording #78457263565 Logs
Banner_DisplayedOnFirstRun Recording #78457263243 Logs
Banner_DisplayedWithExplicitFlag Recording #78457263243 Logs
Banner_NotDisplayedWithNoLogoFlag Recording #78457263243 Logs
CertificatesClean_RemovesCertificates Recording #78457263677 Logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording #78457263677 Logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording #78457263677 Logs
ConfigSetGet_CreatesNestedJsonFormat Recording #78457263568 Logs
CreateAndRunAspireStarterProject Recording #78457263726 Logs
CreateAndRunAspireStarterProjectWithBundle Recording #78457263705 Logs
CreateAndRunEmptyAppHostProject Recording #78457263058 Logs
CreateAndRunJavaEmptyAppHostProject Recording #78457263056 Logs
CreateAndRunJsReactProject Recording #78457263524 Logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording #78457263726 Logs
CreateAndRunPythonReactProject Recording #78457263472 Logs
CreateAndRunTypeScriptEmptyAppHostProject Recording #78457263518 Logs
CreateAndRunTypeScriptStarterProject Recording #78457263562 Logs
CreateJavaAppHostWithViteApp Recording #78457262858 Logs
CreateTypeScriptAppHostWithViteApp_AllowsGuestAppPackageManagerToDiffer Recording #78457263423 Logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording #78457263423 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording #78457263319 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording #78457263319 Logs
DashboardRunWithOtelTracesReturnsNoTraces Recording #78457263319 Logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording #78457263319 Logs
DeployK8sBasicApiService Recording #78457263395 Logs
DeployK8sWithExternalHelmChart Recording #78457263664 Logs
DeployK8sWithGarnet Recording #78457263151 Logs
DeployK8sWithMongoDB Recording #78457263511 Logs
DeployK8sWithMySql Recording #78457263510 Logs
DeployK8sWithPostgres Recording #78457263739 Logs
DeployK8sWithRabbitMQ Recording #78457263714 Logs
DeployK8sWithRedis Recording #78457263801 Logs
DeployK8sWithSqlServer Recording #78457263402 Logs
DeployK8sWithValkey Recording #78457263006 Logs
DeployTypeScriptAppToKubernetes Recording #78457263660 Logs
DescribeCommandResolvesReplicaNames Recording #78457263313 Logs
DescribeCommandShowsRunningResources Recording #78457263313 Logs
DetachFormatJsonProducesValidJson Recording #78457263638 Logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording #78457263638 Logs
DoPublishAndDeployListStepsWork Recording #78457263771 Logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording #78457263307 Logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording #78457262909 Logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording #78457263249 Logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording #78457263249 Logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording #78457263249 Logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78457263097 Logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording #78457263423 Logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording #78457263568 Logs
GlobalMigration_HandlesMalformedLegacyJson Recording #78457263568 Logs
GlobalMigration_PreservesAllValueTypes Recording #78457263568 Logs
GlobalMigration_SkipsWhenNewConfigExists Recording #78457263568 Logs
GlobalSettings_MigratedFromLegacyFormat Recording #78457263568 Logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78457263097 Logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording #78457263423 Logs
InteractiveCSharpInitCreatesExpectedFiles Recording #78457263152 Logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording #78457263575 Logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording #78457263670 Logs
LatestCliCanStartStableChannelAppHost Recording #78457263726 Logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording #78457263726 Logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording #78457263028 Logs
LogsCommandShowsResourceLogs Recording #78457263725 Logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording #78457263429 Logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording #78457263429 Logs
PsCommandListsRunningAppHost Recording #78457263183 Logs
PsFormatJsonOutputsOnlyJsonToStdout Recording #78457263183 Logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording #78457263741 Logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording #78457263741 Logs
PublishWithDockerComposeServiceCallbackSucceeds Recording #78457263741 Logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording #78457263741 Logs
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries Recording #78457263309 Logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording #78457263309 Logs
RestoreGeneratesSdkFiles Recording #78457263785 Logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording #78457263204 Logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording #78457263204 Logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording #78457263601 Logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording #78457263691 Logs
RunReportsSyntaxErrorsForDotNetAppHost Recording #78457263566 Logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording #78457263566 Logs
SecretCrudOnDotNetAppHost Recording #78457263170 Logs
SecretCrudOnTypeScriptAppHost Recording #78457263729 Logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording #78457263786 Logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording #78457263635 Logs
StartReportsSyntaxErrorsForDotNetAppHost Recording #78457263566 Logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording #78457263566 Logs
StopAllAppHostsFromAppHostDirectory Recording #78457263683 Logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording #78457263297 Logs
StopNonInteractiveSingleAppHost Recording #78457263683 Logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording #78457263433 Logs
StopWithNoRunningAppHostExitsSuccessfully Recording #78457263180 Logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording #78457263204 Logs
UpdateProjectChannelToStable_CSharpEmptyAppHost_PreservesAspireConfigChannel Recording #78457263069 Logs
UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel Recording #78457263069 Logs
UpdateProjectChannelToStable_TypeScriptSingleFileInit_PreservesAspireConfigChannel Recording #78457263069 Logs
UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel Recording #78457263069 Logs

📹 Recordings uploaded automatically from CI run #26623717661

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.

3 participants