.Net核心IHostedService后台任务异常不会终止应用程序

时间:2019-04-02 20:28:24

标签: c# .net

我有一个程序,当IHostedService后台任务遇到特定情况时,需要终止该程序。我希望通过在后台任务中抛出一个异常来实现此目的,该异常会被踢到主要功能上。然后,我可以触发取消令牌来杀死其他后台任务。 我的问题是,当我抛出异常时,它杀死了任务,仅此而已。其他所有东西都继续运行。有没有办法做到这一点,或者有更好的办法去做我想做的事情?还有另一种方法可以让后台任务触发通用的CancellationToken吗?

我在下面的代码中包含了我问题的简化版本。 如果我注释掉“ await Task.Delay(TimeSpan.FromSeconds(1),stoppingToken);”行,该异常完成了我想要的操作,因此可以触发CancellationToken。到位后,任务将停止,但程序不会。

注意:在我的代码中,我运行了更多的IHostedServices,这就是为什么我试图触发cancelSource.Cancel()

<script src="https://code.highcharts.com/maps/modules/map.js"></script>

1 个答案:

答案 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