Environment.Exit 后托管服务未终止

Mic*_*ino 7 .net-core

我有一个带有托管服务的 .NET Core 3.1 应用程序,该应用程序在 Windows 上作为控制台应用程序运行。

如果出现错误,我会尝试使用Environment.Exit(1).

现在的问题是,如果Enviroment.Exit()在任何awaitin之前调用ExecuteAsync,应用程序不会终止。它记录Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.然后无限期地挂起。
当我在调用Enviroment.Exit()它之前等待任何东西时也会记录它,但它会按预期终止。

这是我可以想出的最简单的代码来重现问题。
NotTerminatingWorker挂起永远的TerminatingWorker终止。唯一的区别是一个微小的Task.Delay


  public class Program {
    public static async Task Main(string[] args) {
      using var host = CreateHostBuilder(args).Build();
      await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) {
      return Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) => { services.AddHostedService<NotTerminatingWorker>(); });
    }
  }


  public class NotTerminatingWorker : BackgroundService {
    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
      Environment.Exit(1);
    }
  }

  public class TerminatingWorker : BackgroundService {
    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
      await Task.Delay(1);
      Environment.Exit(1);
    }
  }
Run Code Online (Sandbox Code Playgroud)

我希望两者的行为方式相同,但显然情况并非如此。
对此的任何解释将不胜感激!

更新:该应用程序应该能够作为控制台应用程序和 Windows 服务运行。如果它崩溃,则需要非零返回码才能重新启动它。显然 Windows 不会重新启动以代码 0 退出的服务。

Ste*_*ary 14

我相信您看到的行为是 .NET Core 运行时如何启动的副作用:它调用ExecuteAsync每个后台工作程序,然后等待它完成。所以同步ExecuteAsync会导致问题。我曾经Task.Run解决过这个问题。

如果出现错误,我会尝试使用 Environment.Exit(1) 终止工作程序。

我建议根本不要使用Environment.Exit。相反,通过注入IHostApplicationLifetime和调用StopApplication. 这将触发stoppingToken你的每个后台服务,如果他们忽略它,它们将在超时后被强行终止。

  • 在“hostApplicationLifetime.StopApplication();”之前使用“Environment.ExitCode = 1;”似乎有效。 (6认同)
  • @MichaelSandino:您是否使用“WindowsServiceLifetime”而不是[“ConsoleLifetime”,它将“Environment.ExitCode”设置为“0”](https://github.com/dotnet/extensions/blob/10a59dd91a008fd6bcfc3fbf3978d77f8967b0e1/src/Hosting /Hosting/src/Internal/ConsoleLifetime.cs#L89)?`WindowsServiceLifetime` 有[它自己的 `ExitCode`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.windowsservices.windowsservicelifetime?view=dotnet-plat-ext-3.1#特性)。 (2认同)