任务完成后 IHost 未返回
Posted
技术标签:
【中文标题】任务完成后 IHost 未返回【英文标题】:IHost not returning when Task completed 【发布时间】:2022-01-15 07:15:44 【问题描述】:我正在编写一个 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();
永远不会返回(除非我执行 CTRL+C)。
目前我不完全确定我做错了什么。谁能指出我的写作方向?
【问题讨论】:
根据显示的代码,我看不到任何会导致主机停止的情况。 我很好奇您是如何配置服务的。如果默认注册完成,您手动解决的所有内容都会自动注入,为什么还要使用工厂委托。? 【参考方案1】:根据显示的代码,我看不到任何会导致主机停止的情况。
托管服务一旦启动,就与应用程序主机本身无关。所以即使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
会为您添加日志记录和主机生命周期
【讨论】:
谢谢,IHostApplicationLifetime 的注入对我有用。 就服务配置的原因而言,简单的答案是我试图对问题进行排序并尝试了一些不同的方法。接下来我会回去重新检查。以上是关于任务完成后 IHost 未返回的主要内容,如果未能解决你的问题,请参考以下文章