我有一个程序,当IHostedService后台任务遇到特定情况时,需要终止该程序。我希望通过在后台任务中抛出一个异常来实现此目的,该异常会被踢到主要功能上。然后,我可以触发取消令牌来杀死其他后台任务。 我的问题是,当我抛出异常时,它杀死了任务,仅此而已。其他所有东西都继续运行。有没有办法做到这一点,或者有更好的办法去做我想做的事情?还有另一种方法可以让后台任务触发通用的CancellationToken吗?
我在下面的代码中包含了我问题的简化版本。 如果我注释掉“ await Task.Delay(TimeSpan.FromSeconds(1),stoppingToken);”行,该异常完成了我想要的操作,因此可以触发CancellationToken。到位后,任务将停止,但程序不会。
注意:在我的代码中,我运行了更多的IHostedServices,这就是为什么我试图触发cancelSource.Cancel()
<script src="https://code.highcharts.com/maps/modules/map.js"></script>
答案 0 :(得分:2)
使用ExecuteAsync
运算符注释await
方法中的唯一行,使您的代码同步运行。如果我们查看BackgroundService.StartAsync
的来源,就会发现它检查了_executingTask.IsCompleted
并返回了包含您的异常的任务,以防ExecuteAsync
方法中没有任何等待,否则它将返回Task.CompletedTask
,您将无法在ExecuteAsync
方法中从Main
捕获此异常。
您可以使用ApplicationLifetime来管理您的服务,这些服务可以注入您的所有后台服务中,例如,您可以在ExecuteMethod
中捕获异常并调用ApplicationLifetime.StopApplication
示例:
static async Task Main(string[] args)
{
await new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<TestService>();
services.AddHostedService<TestService2>();
})
.Build()
.RunAsync();
Console.WriteLine("App stoped");
}
服务1
public class TestService : BackgroundService
{
private readonly IApplicationLifetime _applicationLifetime;
public TestService(IApplicationLifetime applicationLifetime)
{
_applicationLifetime = applicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!_applicationLifetime.ApplicationStopping.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1), _applicationLifetime.ApplicationStopping);
Console.WriteLine("running service 1");
throw new ApplicationException("OOPS!!");
}
}
catch (ApplicationException)
{
_applicationLifetime.StopApplication();
}
}
}
服务2
public class TestService2 : BackgroundService
{
private readonly IApplicationLifetime _applicationLifetime;
public TestService2(IApplicationLifetime applicationLifetime)
{
_applicationLifetime = applicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!_applicationLifetime.ApplicationStopping.IsCancellationRequested)
{
await Task.Delay(100, _applicationLifetime.ApplicationStopping);
Console.WriteLine("running service 2");
}
}
catch (ApplicationException)
{
_applicationLifetime.StopApplication();
}
}
}
输出:
running service 2
running service 2
running service 1
App stoped