Add startup timeout options to Aspire CLI#16686
Open
sebastienros wants to merge 2 commits intomainfrom
Open
Conversation
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>
Contributor
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16686Or
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>
Contributor
There was a problem hiding this comment.
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
--timeoutsupport (and validation) toaspire runandaspire start, and propagate the configured timeout into detached AppHost launch waiting logic. - Introduce an
IDetachedProcessLauncherabstraction 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/detachedrundoesn’t orphan an AppHost/build process.
if (!result.ChildProcess.HasExited)
{
try
{
result.ChildProcess.Kill();
| catch (TimeoutException) | ||
| { | ||
| runActivity?.SetTag(TelemetryConstants.Tags.ErrorType, "startup_timeout"); | ||
| CancelAppHostStartup(runCancellationTokenSource); |
Comment on lines
+264
to
+275
| var startupTimeout = TimeSpan.FromSeconds(timeoutSeconds); | ||
| using var runCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); | ||
|
|
||
| // Start the project run as a pending task - we'll handle UX while it runs | ||
| var pendingRun = project.RunAsync(context, cancellationToken); | ||
| var pendingRun = project.RunAsync(context, runCancellationTokenSource.Token); | ||
|
|
||
| // Wait for the build to complete first (project handles its own build status spinners) | ||
| var buildSuccess = await buildCompletionSource.Task.WaitAsync(cancellationToken); | ||
| bool buildSuccess; | ||
| try | ||
| { | ||
| buildSuccess = await buildCompletionSource.Task.WaitAsync(startupTimeout, cancellationToken); | ||
| } |
Comment on lines
+44
to
+53
| /// <summary> | ||
| /// Asynchronously waits for the process to exit. | ||
| /// </summary> | ||
| Task WaitForExitAsync(CancellationToken cancellationToken); | ||
|
|
||
| /// <summary> | ||
| /// Kills the process. | ||
| /// </summary> | ||
| void Kill(); | ||
| } |
| if (!_process.HasExited) | ||
| { | ||
| _logger.LogDebug("{FileName}({ProcessId}) wait was canceled, killing it", FileName, _process.Id); | ||
| _process.Kill(entireProcessTree: true); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
AppHost builds or startups can take longer than the CLI's default wait, causing
aspire startandaspire runto fail without a clear way to extend the startup wait. This reuses the existingaspire wait --timeoutsemantics foraspire startandaspire run, including detached launches, and updates the timeout guidance to tell users to retry with a higher--timeoutvalue.This also makes detached process launch testable and ensures canceled process waits terminate the spawned process tree, so a timed-out
aspire rundoes not leave a build or AppHost process running after the CLI exits.Fixes # (issue)
N/A
Checklist
<remarks />and<code />elements on your triple slash comments?aspire.devissue: