如何从ExecuteAsync中的代码取消dotnet core工作进程?

7

我有一个dotnet核心的工作进程,希望在某些条件下关闭该进程。

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
     {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("This is a worker process");
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

                 if (condition == true)
                  //do something to basically shutdown the worker process with failure code.
                
                await Task.Delay(2000, stoppingToken);                
            }
        }

我该如何实现这个功能?我试过跳出循环,但那并不能真正关闭工作进程。
//----this does not work-----
//even after doing this, Ctrl-C has to be done to shutdown the worker.
if (condition == true) break; 

2
抛出一个详细说明失败的异常?如果你真的想要强制退出,你可以使用 Environment.FailFast,但这会跳过所有清理工作,所以最好将退出的负担转移到最高层面(捕获异常、记录日志,然后使用 Environment.Exit)。 - Jeroen Mostert
1
抛出异常还是您可以访问CancellationTokenSource?如果是后者,另一种方法是调用Cancel - Igor
2个回答

14

退出IHostedService并不会终止应用程序本身。一个应用程序可能运行多个IHostedService,因此让其中一个关闭整个应用程序是没有意义的。

要终止应用程序,托管服务类必须接受一个IHostApplicationLifetime实例,并在需要终止应用程序时调用StopApplication。该接口将由DI中间件进行注入:

class MyService:BackgroundService
{
    IHostApplicationLifetime _lifetime;

    public MyService(IHostApplicationLifetime lifetime)
    {
        _lifetime=lifetime;
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            ...
            if (condition == true)
            {
                   _lifeTime.StopApplication();
                   return;
            }
                 
            ...            
        }
    }

}

这将向所有其他后台服务发送信号以优雅地终止它们,并导致Run()RunAsync()返回,从而退出应用程序。

抛出异常也不会结束应用程序

如果服务希望终止进程,则必须确保调用StopApplication,例如:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    try 
    {
        ...
    }
    catch(Exception exc)
    {
        //log the exception then
        _lifetime.StopApplication();
    }

}

@134204 我们如何最好地处理这样的情况,比如我们必须打开一个数据库连接,但失败了?打开数据库连接的最佳位置是什么 - 你会推荐什么?是在 StartAsync 中吗? - unlimit
在使用using块时,它应该放置在将要使用的位置。没有必要长时间保持连接开放,连接池确保关闭和重新打开一个连接不花费任何代价。这就是为什么所有的教程都显示在using块中创建连接的原因。 - Panagiotis Kanavos
锁定在事务或连接存在的情况下保持活动状态,因此长期存在的连接会积累锁定并可能阻塞其他连接或导致死锁。 - Panagiotis Kanavos

0
最好的方法是使用:

Environement.Exit(1);

在你的if语句中。

如果你正在使用BackgroundWorker类编写Windows服务,那么这一点尤为重要,这样Windows服务管理系统才能正确使用配置的恢复选项。

例如,请参见使用BackgroundService创建Windows服务


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接