You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
aspire stop — invoked from our TypeScript AppHost test harness's cleanup step, after the test body has already completed successfully — hangs indefinitely instead of exiting, consuming CI's full 7-minute hang-dump budget before the process is force-killed. This causes an otherwise fully-passing test to report as a failure (exit code 7/134), and has been our single largest source of CI flakiness: we estimate this accounts for roughly half of our main branch test failures over the past two weeks, recurring across multiple, unrelated integrations (Meilisearch x2, Floci, RustFs — all Aspire CLI 13.5.0).
We added extra diagnostics/log-capture around our TypeScript AppHost tests in CommunityToolkit/Aspire#1607 specifically to get visibility into this, and it's what let us pin down the following.
Expected Behavior
aspire stop should either complete promptly or fail with a clear, bounded error — it should never hang indefinitely.
Steps To Reproduce
We don't have a minimal repro (this appears tied to a shutdown-timing race, so it's intermittent), but the consistent signature across every occurrence we've captured, right as the AppHost begins tearing down:
fail: Aspire.Hosting.Backchannel.AuxiliaryBackchannelService[0]
Error handling client connection on auxiliary backchannel
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Aspire.Hosting.Backchannel.AuxiliaryBackchannelService.HandleClientConnectionAsync(Socket clientSocket, CancellationToken stoppingToken) in .../AuxiliaryBackchannelService.cs:line 157
...followed by:
The aspire stop CLI process going completely silent, with no further log lines at all.
The process eventually being SIGKILLed after the ~7 minute hang-dump timeout; attempts to take a memory dump of it fail with Microsoft.Diagnostics.NETCore.Client.ServerNotAvailableException: Unable to connect to Process <pid>, consistent with it being blocked on I/O rather than executing.
In every case, aspire wait <resource> had already completed successfully and the test body itself had passed — only the cleanup call to aspire stop hangs.
Reading AuxiliaryBackchannelService.HandleClientConnectionAsync (current main), we believe the mechanism is:
privateasyncTaskHandleClientConnectionAsync(SocketclientSocket,CancellationTokenstoppingToken){try{
...var rpcTarget =newAuxiliaryBackchannelRpcTarget(serviceProvider.GetRequiredService<ILogger<AuxiliaryBackchannelRpcTarget>>(),// throws ObjectDisposedException here during shutdown
...);usingvarstream=newNetworkStream(clientSocket,ownsSocket:true);// never reached
...}catch(Exceptionex){logger.LogError(ex,"Error handling client connection on auxiliary backchannel");// logs and returns — clientSocket never disposed}}
Connections are dispatched from the accept loop as untracked fire-and-forget tasks (_ = Task.Run(...)), so the AppHost's DI container can be disposed mid-shutdown while a handler is still resolving services from it. When that throws, execution never reaches the using var stream = new NetworkStream(clientSocket, ownsSocket: true) that would own/dispose the socket — so the accepted socket appears to be leaked, and the client (aspire stop, mid handshake) is left blocked reading from a connection that will never send data or close.
Exceptions (if any)
See log excerpt above.
Anything else?
Adam Ratzman (@adamint)'s Bound AppHost auxiliary backchannel handshake #19832 ("Bound AppHost auxiliary backchannel handshake", fixing aspire run --start-debug-session hangs while stopping an orphaned AppHost #19269) adds a client-side 10-second deadline around this handshake — a good mitigation for the symptom (a caller like aspire stop/aspire ps will no longer hang forever), and would likely have prevented our CI failures from consuming the full hang-dump window. However, it doesn't fix the underlying problem: aspire stop would still time out and fail to actually stop the AppHost cleanly in this scenario — it converts a silent hang into a bounded failure, but aspire stop still doesn't do its job. The server-side socket leak / DI-disposal race above looks unaddressed on main as of this writing.
Bound AppHost auxiliary backchannel handshake #19832 is not in any released version yet (present on main/unreleased release/14.0 only; absent from release/13.5, which is what we currently run in CI at 13.5.0–13.5.4).
Aspire CLI: 13.5.0 (also appears present on current main)
Happy to help validate a fix against our downstream repro pattern if useful.
Is there an existing issue for this?
Describe the bug
aspire stop— invoked from our TypeScript AppHost test harness's cleanup step, after the test body has already completed successfully — hangs indefinitely instead of exiting, consuming CI's full 7-minute hang-dump budget before the process is force-killed. This causes an otherwise fully-passing test to report as a failure (exit code 7/134), and has been our single largest source of CI flakiness: we estimate this accounts for roughly half of ourmainbranch test failures over the past two weeks, recurring across multiple, unrelated integrations (Meilisearch x2, Floci, RustFs — all Aspire CLI 13.5.0).We added extra diagnostics/log-capture around our TypeScript AppHost tests in CommunityToolkit/Aspire#1607 specifically to get visibility into this, and it's what let us pin down the following.
Expected Behavior
aspire stopshould either complete promptly or fail with a clear, bounded error — it should never hang indefinitely.Steps To Reproduce
We don't have a minimal repro (this appears tied to a shutdown-timing race, so it's intermittent), but the consistent signature across every occurrence we've captured, right as the AppHost begins tearing down:
...followed by:
aspire stopCLI process going completely silent, with no further log lines at all.aspire stopprocess is the one left hanging.Microsoft.Diagnostics.NETCore.Client.ServerNotAvailableException: Unable to connect to Process <pid>, consistent with it being blocked on I/O rather than executing.aspire wait <resource>had already completed successfully and the test body itself had passed — only the cleanup call toaspire stophangs.Example job with captured logs: https://github.com/CommunityToolkit/Aspire/actions/runs/35761857913/job/106861834507 (Meilisearch), artifact
ts-app-host-logs-Hosting.Meilisearch.Tests-ubuntu-latestshows the CLI log going silent immediately after this exception.Reading
AuxiliaryBackchannelService.HandleClientConnectionAsync(currentmain), we believe the mechanism is:Connections are dispatched from the accept loop as untracked fire-and-forget tasks (
_ = Task.Run(...)), so the AppHost's DI container can be disposed mid-shutdown while a handler is still resolving services from it. When that throws, execution never reaches theusing var stream = new NetworkStream(clientSocket, ownsSocket: true)that would own/dispose the socket — so the accepted socket appears to be leaked, and the client (aspire stop, mid handshake) is left blocked reading from a connection that will never send data or close.Exceptions (if any)
See log excerpt above.
Anything else?
aspire run --start-debug-sessionhangs while stopping an orphaned AppHost #19269) adds a client-side 10-second deadline around this handshake — a good mitigation for the symptom (a caller likeaspire stop/aspire pswill no longer hang forever), and would likely have prevented our CI failures from consuming the full hang-dump window. However, it doesn't fix the underlying problem:aspire stopwould still time out and fail to actually stop the AppHost cleanly in this scenario — it converts a silent hang into a bounded failure, butaspire stopstill doesn't do its job. The server-side socket leak / DI-disposal race above looks unaddressed onmainas of this writing.main/unreleasedrelease/14.0only; absent fromrelease/13.5, which is what we currently run in CI at 13.5.0–13.5.4).main)