Skip to content

Support AppHost startup timeout env var#16686

Open
sebastienros wants to merge 5 commits intomainfrom
sebros/start-timeout
Open

Support AppHost startup timeout env var#16686
sebastienros wants to merge 5 commits intomainfrom
sebros/start-timeout

Conversation

@sebastienros
Copy link
Copy Markdown
Contributor

@sebastienros sebastienros commented May 1, 2026

Description

AppHost builds or startups can take longer than the CLI's default wait, causing aspire start and aspire run to fail without a clear escape hatch for slow machines or CI environments. This adds the ASPIRE_CLI_START_TIMEOUT environment variable for aspire start and aspire run, including detached launches, while keeping aspire wait --timeout as the explicit wait-command option.

The timeout guidance now tells users to set ASPIRE_CLI_START_TIMEOUT to a higher value, and invalid values produce a clear error. This also keeps the process cleanup fixes from the earlier review feedback so a timed-out aspire run does not leave a build or AppHost process running after the CLI exits.

Fixes # (issue)
N/A

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
  • Does the change require an update in our Aspire docs?

Reuse the wait timeout option for start and run so slow AppHost builds or startups can wait longer than the default and show actionable timeout guidance.

Cover start, run, detached startup, invalid timeout validation, and canceled process cleanup with CLI tests.

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

github-actions Bot commented May 1, 2026

🚀 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 -- 16686

Or

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

Replace the custom advancing time provider with Microsoft.Extensions.Time.Testing.FakeTimeProvider configured with AutoAdvanceAmount.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Pull request overview

This PR extends the Aspire CLI startup experience by adding configurable startup timeouts to aspire run and aspire start, aligning them with existing aspire wait --timeout semantics and improving timeout guidance. It also refactors detached launching to be testable and updates process-wait cancellation behavior to reduce the risk of orphaned processes.

Changes:

  • Add --timeout support (and validation) to aspire run and aspire start, and propagate the configured timeout into detached AppHost launch waiting logic.
  • Introduce an IDetachedProcessLauncher abstraction to make detached launching testable and injectable.
  • Improve timeout messaging (including localization resources) and add process cancellation coverage to ensure spawned processes are terminated when waits are canceled.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs Registers the default detached process launcher in the test DI container.
tests/Aspire.Cli.Tests/TestServices/TestDetachedProcessLauncher.cs Adds a test double for detached process launching plus a test TimeProvider.
tests/Aspire.Cli.Tests/DotNet/ProcessExecutionTests.cs Adds a regression test ensuring cancellation kills the spawned process.
tests/Aspire.Cli.Tests/Commands/StartCommandTests.cs Adds coverage for start --timeout parsing/validation and timeout behavior in detached launch.
tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs Adds coverage for run --timeout parsing/validation and detached timeout behavior.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hant.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hans.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.tr.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.ru.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.pt-BR.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.pl.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.ko.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.ja.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf Updates localized resource entry for the new formatted timeout guidance string.
src/Aspire.Cli/Resources/RunCommandStrings.resx Updates the timeout message to include the configured seconds and guidance to retry with higher --timeout.
src/Aspire.Cli/Program.cs Registers IDetachedProcessLauncher in the CLI host DI container.
src/Aspire.Cli/Processes/IDetachedProcessLauncher.cs Introduces the detached process launcher/process abstractions and a default implementation.
src/Aspire.Cli/DotNet/ProcessExecution.cs Ensures cancellation of WaitForExitAsync kills the process tree.
src/Aspire.Cli/Commands/WaitCommand.cs Centralizes timeout option creation and timeout validation for reuse.
src/Aspire.Cli/Commands/StartCommand.cs Adds --timeout support to start and forwards it to detached launch waiting.
src/Aspire.Cli/Commands/RunCommand.cs Adds --timeout support to run, applies it to build/backchannel waits, and threads it through detached launch.
src/Aspire.Cli/Commands/AppHostLauncher.cs Adds optional --timeout to shared launch options and uses it for detached backchannel wait; uses injectable detached launcher.
Comments suppressed due to low confidence (1)

src/Aspire.Cli/Commands/AppHostLauncher.cs:350

  • On timeout, this kills only the detached child CLI process. Since the child may have already spawned the AppHost (grandchild), killing just the parent process can leave the AppHost running. Consider ensuring the kill operation terminates the entire process tree (consistent with other CLI process shutdown paths) so a timed-out start/detached run doesn’t orphan an AppHost/build process.
            if (!result.ChildProcess.HasExited)
            {
                try
                {
                    result.ChildProcess.Kill();

Comment thread src/Aspire.Cli/Commands/RunCommand.cs Outdated
Comment thread src/Aspire.Cli/Commands/RunCommand.cs
Comment thread src/Aspire.Cli/Processes/IDetachedProcessLauncher.cs
Comment thread src/Aspire.Cli/DotNet/ProcessExecution.cs Outdated
Use a single timeout budget for run startup, observe pending AppHost runs during timeout cleanup, and make detached process termination explicit about process-tree cleanup.

Keep cancellation propagation reliable when process-tree termination fails.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl
Copy link
Copy Markdown
Contributor

This should be an env variable not an argument.

Replace the run/start timeout options with ASPIRE_CLI_START_TIMEOUT_SECONDS while keeping aspire wait --timeout unchanged.

Update timeout guidance and validation to point users at the environment variable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros sebastienros changed the title Add startup timeout options to Aspire CLI Support AppHost startup timeout env var May 4, 2026
Use ASPIRE_CLI_START_TIMEOUT to match existing Aspire timeout environment variable naming.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros
Copy link
Copy Markdown
Contributor Author

Changed to using an ENV as it makes more sense

@sebastienros sebastienros reopened this May 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

🎬 CLI E2E Test Recordings — 55 recordings uploaded (commit 44a3be1)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View Recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View Recording
DeployK8sBasicApiService ▶️ View Recording
DeployK8sWithGarnet ▶️ View Recording
DeployK8sWithMongoDB ▶️ View Recording
DeployK8sWithMySql ▶️ View Recording
DeployK8sWithPostgres ▶️ View Recording
DeployK8sWithRabbitMQ ▶️ View Recording
DeployK8sWithSqlServer ▶️ View Recording
DeployK8sWithValkey ▶️ View Recording
DeployTypeScriptAppToKubernetes ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View Recording
DoListStepsShowsPipelineSteps ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording

📹 Recordings uploaded automatically from CI run #25348131669

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