aspire icon indicating copy to clipboard operation
aspire copied to clipboard

Aspire fails to trigger IHostApplicationLifetime.ApplicationStopping in hosted projects on Windows (via Dashboard Stop or AppHost Ctrl+C)

Open fortoken opened this issue 8 months ago • 3 comments

Is there an existing issue for this?

  • [x] I have searched the existing issues

Describe the bug

On the Windows operating system, when a .NET project (e.g., a Worker Service or ASP.NET Core application) is hosted by Aspire AppHost, the IHostApplicationLifetime.ApplicationStopping event registered within it fails to trigger. This occurs regardless of whether the stop action is initiated via the Aspire Dashboard UI or by pressing Ctrl+C in the terminal running the AppHost to stop the entire application. This prevents the application from executing its graceful shutdown logic (e.g., processing pending tasks in memory or releasing resources), potentially causing data loss or inconsistent states.

Expected Behavior

Whether stopping a single resource via the Aspire Dashboard or stopping the entire application via Ctrl+C in the AppHost terminal, the Aspire AppHost should send the appropriate signal (e.g., SIGINT or an equivalent mechanism) to its managed child processes. This signal should trigger the IHostApplicationLifetime.ApplicationStopping event within the child process, allowing the application to perform graceful shutdown.

Steps To Reproduce

  1. Create an Aspire Solution: Set up a basic Aspire solution with an AppHost project and a target .NET project (e.g., ASP.NET Core Worker Service or Web API, referred to as YourServiceProject below).
  2. Implement ApplicationStopping Handler in Service Project: In YourServiceProject/Program.cs, inject IHostApplicationLifetime and register a handler for the ApplicationStopping event. Include clear logging within the handler:
    var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
    var logger = app.Services.GetRequiredService<ILogger<Program>>(); 
    lifetime.ApplicationStopping.Register(() => {
        logger.LogInformation(">>>>>>>>>> ApplicationStopping triggered! Timestamp: {Timestamp}", DateTime.UtcNow.ToString("O"));
        // Optional: Add Thread.Sleep(1000) with logging to verify execution duration
    });
    
  3. (Optional but Recommended) Add File Logging: Configure file logging (e.g., using NetEscapades.Extensions.Logging.RollingFile) in YourServiceProject to capture logs reliably, especially during shutdown.
  4. (Optional but Recommended) Add Background Service: Include a simple BackgroundService that depends on the stoppingToken to simulate work and graceful shutdown logic (e.g., processing items from a channel).
  5. Ensure Aspire Environment is Set: Verify that the DOTNET_ASPIRE_ENVIRONMENT variable is correctly set for the service process when launched by AppHost (e.g., via launchSettings.json or WithEnvironment).
  6. Run the AppHost: Execute dotnet run --project YourAppHost.csproj in a terminal on Windows.
  7. Attempt Stop via Dashboard: Open the Aspire Dashboard, select the YourServiceProject resource, and click the "Stop" button.
  8. Observe Logs: Check the logs for YourServiceProject (console output or file logs). Result: The "ApplicationStopping triggered!" log message is not present.
  9. Restart the AppHost: Run dotnet run --project YourAppHost.csproj again.
  10. Attempt Stop via Ctrl+C: In the terminal window running the AppHost, press Ctrl+C.
  11. Observe Logs: Check the logs for YourServiceProject. Result: The "ApplicationStopping triggered!" log message is not present.
  12. Verify Standalone Behavior: Run YourServiceProject directly (dotnet run from its directory) and press Ctrl+C. Result: The "ApplicationStopping triggered!" log message is present.

Exceptions (if any)

No exceptions are thrown. The issue is the absence of the expected event trigger.

.NET Version info

`PS D:> dotnet --info .NET SDK: Version: 9.0.300-preview.0.25177.5 Commit: 3d5b396331 Workload version: 9.0.300-manifests.1e5233e8 MSBuild version: 17.14.0-preview-25175-08+5880e1c75

运行时环境: OS Name: Windows OS Version: 10.0.26100 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\9.0.300-preview.0.25177.5\

已安装 .NET 工作负载: 没有要显示的已安装工作负载。 配置为在安装新清单时使用 loose manifests。

Host: Version: 9.0.3 Architecture: x64 Commit: 831d23e561

.NET SDKs installed: 9.0.200 [C:\Program Files\dotnet\sdk] 9.0.300-preview.0.25177.5 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 6.0.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 9.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 9.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 8.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 9.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found: x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables: Not set

global.json file: Not found

Learn more: https://aka.ms/dotnet/info

Download .NET: https://aka.ms/dotnet/download`

Anything else?

  • Aspire Version: 9.2.0+0fcb1e9885266c1700c49c16513a6d97480bb058 (or user's version from AppHost logs)
  • Operating System: Windows 10/11

Summary of Test Results:

Scenario ApplicationStopping Triggered (per logs)? Graceful Shutdown Logs (if applicable)?
Stop Service via Dashboard No No
Stop App via AppHost Terminal Ctrl+C (with background svcs) No No
Stop App via AppHost Terminal Ctrl+C (background svcs commented) No (N/A)
Run Service Standalone + Ctrl+C Yes Yes

fortoken avatar Apr 22 '25 17:04 fortoken

I’m assuming these tests are on windows only

davidfowl avatar Apr 23 '25 02:04 davidfowl

Unfortunately Windows doesn't have an API to allow us to send CTRL-C to a child process in either of these cases.

dbreshears avatar Apr 28 '25 18:04 dbreshears

@dbreshears it does but dcp needs to change how it creates the process (to use a process group)

davidfowl avatar Apr 28 '25 18:04 davidfowl

We just updated the orchestrator to send ctrl+break when closing processes on Windows; I believe that should fix this particular issue.

danegsta avatar May 09 '25 00:05 danegsta

I've confirmed that I hit ApplicationStopping with the updated orchestrator. I'm going to close this issue out since we seem to be fixed in main, but let us know if you run into any further issues.

danegsta avatar May 09 '25 00:05 danegsta