Skip to content

Commit 4ed44ce

Browse files
github-actions[bot]Copilotmitchdenny
authored
[release/9.4] Fix CLI hanging when dashboard fails to start by implementing ResourceFailedException (#10614)
* Initial plan * Implement ResourceFailedException and update hosting/CLI to handle dashboard failures Co-authored-by: mitchdenny <[email protected]> * Add comprehensive tests for ResourceFailedException handling Co-authored-by: mitchdenny <[email protected]> * Address feedback: Move exception translation to AppHostRpcTarget and rename to DashboardStartupException Co-authored-by: mitchdenny <[email protected]> * Tweak wait logic. * WIP: Working around exception JSON-RPC tear down issue. * Fix test cases. * Remove health check for dashboard. * Copilot feedback. * Remove whitespace change. * PR feedback. * Set default dashboard healthy state. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mitchdenny <[email protected]> Co-authored-by: Mitch Denny <[email protected]>
1 parent e9c53d2 commit 4ed44ce

27 files changed

+302
-114
lines changed

src/Aspire.Cli/Backchannel/AppHostBackchannel.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Aspire.Cli.Backchannel;
1414
internal interface IAppHostBackchannel
1515
{
1616
Task RequestStopAsync(CancellationToken cancellationToken);
17-
Task<(string BaseUrlWithLoginToken, string? CodespacesUrlWithLoginToken)> GetDashboardUrlsAsync(CancellationToken cancellationToken);
17+
Task<DashboardUrlsState> GetDashboardUrlsAsync(CancellationToken cancellationToken);
1818
IAsyncEnumerable<BackchannelLogEntry> GetAppHostLogEntriesAsync(CancellationToken cancellationToken);
1919
IAsyncEnumerable<RpcResourceState> GetResourceStatesAsync(CancellationToken cancellationToken);
2020
Task ConnectAsync(string socketPath, CancellationToken cancellationToken);
@@ -46,19 +46,18 @@ await rpc.InvokeWithCancellationAsync(
4646
cancellationToken);
4747
}
4848

49-
public async Task<(string BaseUrlWithLoginToken, string? CodespacesUrlWithLoginToken)> GetDashboardUrlsAsync(CancellationToken cancellationToken)
49+
public async Task<DashboardUrlsState> GetDashboardUrlsAsync(CancellationToken cancellationToken)
5050
{
5151
using var activity = telemetry.ActivitySource.StartActivity();
5252
var rpc = await _rpcTaskCompletionSource.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
5353

5454
logger.LogDebug("Requesting dashboard URL");
5555

56-
var url = await rpc.InvokeWithCancellationAsync<DashboardUrlsState>(
56+
var state = await rpc.InvokeWithCancellationAsync<DashboardUrlsState>(
5757
"GetDashboardUrlsAsync",
5858
[],
5959
cancellationToken);
60-
61-
return (url.BaseUrlWithLoginToken, url.CodespacesUrlWithLoginToken);
60+
return state;
6261
}
6362

6463
public async IAsyncEnumerable<BackchannelLogEntry> GetAppHostLogEntriesAsync([EnumeratorCancellation] CancellationToken cancellationToken)

src/Aspire.Cli/Commands/RunCommand.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
172172
return await backchannel.GetDashboardUrlsAsync(cancellationToken);
173173
});
174174

175+
if (dashboardUrls.DashboardHealthy is false)
176+
{
177+
_interactionService.DisplayError(RunCommandStrings.DashboardFailedToStart);
178+
_interactionService.DisplayLines(runOutputCollector.GetLines());
179+
return ExitCodeConstants.DashboardFailure;
180+
}
181+
175182
_ansiConsole.WriteLine();
176183

177184
var topGrid = new Grid();

src/Aspire.Cli/ExitCodeConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ internal static class ExitCodeConstants
1717
public const int AppHostIncompatible = 9;
1818
public const int ConfigNotFound = 10;
1919
public const int SdkNotInstalled = 11;
20+
public const int DashboardFailure = 12;
2021
}

src/Aspire.Cli/Resources/RunCommandStrings.Designer.cs

Lines changed: 106 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Cli/Resources/RunCommandStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,7 @@
155155
<data name="Logs" xml:space="preserve">
156156
<value>Logs</value>
157157
</data>
158+
<data name="DashboardFailedToStart" xml:space="preserve">
159+
<value>Aspire Dashboard failed to start.</value>
160+
</data>
158161
</root>

src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)