托管服务在Environment.Exit

时间:2020-01-23 13:05:14

标签: .net-core

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

如果发生错误,我尝试使用Environment.Exit(1)终止工作进程。

现在的问题是,如果在Enviroment.Exit()中的任何await之前调用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);
    }
  }

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

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

1 个答案:

答案 0 :(得分:9)

我相信您看到的行为是.NET Core运行时启动方式的副作用:它为每个后台工作程序调用{​​{1}},然后等待它完成。因此,同步ExecuteAsync可能会引起问题。我使用ExecuteAsync来解决此问题。

如果发生错误,我正在尝试使用Environment.Exit(1)终止工作进程。

我建议完全不使用Task.Run。相反,可以通过注入Environment.Exit并调用IHostApplicationLifetime来进行受控关闭。这将为您的每个后台服务触发StopApplication,并且如果它们忽略了它们,它们将在超时后被强制终止。