任务完成后 IHost 不返回

IHost not returning when Task completed

我正在编写 Windows 服务(使用 .NET Core 3.1),使用 BackgroundService,当我想以编程方式停止服务时,我似乎遇到了问题。

我的主要功能如下

static async Task Main(string[] args)
{
    IHost host = null;
    try
    {
        host = CreateService(args).Build();
        await host.RunAsync();
        Console.WriteLine("Ending");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception");
    }
    finally
    {
        if (host is IAsyncDisposable d) await d.DisposeAsync();
    }
}

    public static IHostBuilder CreateService(string[] args) =>

         Host.CreateDefaultBuilder(args)
                .UseWindowsService(options =>
                {
                    options.ServiceName = "My Service";

                })
                .ConfigureServices((hostContext, services) =>
                {
                    IConfiguration configuration = hostContext.Configuration;
                    ServiceOptions options = configuration.GetSection("ServiceOptions").Get<ServiceOptions>();
                    WorkerService sService = new WorkerService();
                    services.AddSingleton(options);
                    services.AddSingleton(sService);

                    services.AddHostedService<WindowsBackgroundService>(service => new WindowsBackgroundService(
                        service.GetService<WorkerService>(),
                        service.GetService<ILogger<WindowsBackgroundService>>(),
                        service.GetService<ServerOptions>()

                    ));
                });

后台服务如下:

public sealed class WindowsBackgroundService : BackgroundService
{
    private WorkerService _workerService;
    private ServerOptions _options;
    private ILogger<WindowsBackgroundService> _logger;

    public WindowsBackgroundService(
        WorkerService workerService, ILogger<WindowsBackgroundService> logger,
        ServiceOptions serviceOptions) => (_workerService, _logger, _options) = (workerService, logger, serviceOptions);

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        bool allDone = false;
        while (!stoppingToken.IsCancellationRequested && !allDone)
        {
            await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
            //  Log to watchdog 

            //  Check if we are in the run window
            if (_options.InActivePeriod())
            {

        
                Console.WriteLine("Process Queue");
               
                var processResult = _workerService.Process(_options);
                if (!processResult && _workerService.FatalError)
                {
                    _workerService = null;
                    allDone = true;
                    Console.WriteLine("Service Quitting");
                }
            }

        }
        Console.WriteLine($"Task Ending {stoppingToken.IsCancellationRequested}");
        return;
    }

    

}

}

所以一切 运行 都应该如此,我 运行 在调试器或命令行下进行此操作(我还没有实际将其安装为 Windows 服务,因为我还在写代码)。 函数 Process 正确执行。如果它遇到无法恢复的错误,它会将它设置为 FatalError 属性,这应该是一个信号,表明整个服务应该停止。任务确实完成了(正确的行被写入控制台)但是行 Console.WriteLine("Ending"); 永远不会执行。看起来 host.RunAsync(); 永远不会 returns(除非我按 CTRL+C)。

我现在不完全确定我做错了什么。谁能指出我的写作方向?

根据显示的代码,我没有看到任何会导致主机停止的东西。

托管服务,一旦启动与应用程序主机本身无关。所以即使ExecuteAsync完成了,那个功能的完成也不代表宿主会停止运行.

您可以考虑将 IHostApplicationLifetime 注入托管服务并明确告诉应用程序以编程方式停止;

例如

public sealed class WindowsBackgroundService : BackgroundService {
    private WorkerService _workerService;
    private ServerOptions _options;
    private ILogger<WindowsBackgroundService> _logger;
    private IHostApplicationLifetime lifetime;

    public WindowsBackgroundService(
        WorkerService workerService, ILogger<WindowsBackgroundService> logger,
        ServiceOptions serviceOptions, IHostApplicationLifetime lifetime) 
            => (_workerService, _logger, _options, this.lifetime) = (workerService, logger, serviceOptions, lifetime);

    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        bool allDone = false;
        while (!stoppingToken.IsCancellationRequested && !allDone) {
            await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
            //  Log to watchdog 

            //  Check if we are in the run window
            if (_options.InActivePeriod()) {
                Console.WriteLine("Process Queue");
               
                var processResult = _workerService.Process(_options);
                if (!processResult && _workerService.FatalError) {
                    _workerService = null;
                    allDone = true;
                    Console.WriteLine("Service Quitting");
                    
                    lifetime.StopApplication(); //SIGNAL APPLICATION TO STOP
                }
            }    
        }
        Console.WriteLine($"Task Ending {stoppingToken.IsCancellationRequested}");
        return;
    }
}

我也很好奇您是如何配置服务的。如果默认注册完成,您手动解决的所有问题都会自动注入,为什么还要使用工厂委托?

//...
.ConfigureServices((hostContext, services) => {
    IConfiguration configuration = hostContext.Configuration;
    ServiceOptions options = configuration.GetSection("ServiceOptions").Get<ServiceOptions>();
    services.AddSingleton(options);

    services.AddSingleton<WorkerService>();

    services.AddHostedService<WindowsBackgroundService>();
});

Host.CreateDefaultBuilder

为您添加了日志记录和主机生命周期