.net core Worker Service 在没有 ctrl+C 的情况下优雅地停止之前迭代 n 次

.net core Worker Service iterate n times before gracefully stop without ctrl+C

我想要实现的是 运行 一个异步任务 n 次然后优雅地完成而无需执行 ctrl+C。我相信我需要使用 IHostLifetime,因为 CancellationToken stoppingToken 是只读的

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IServiceScopeFactory _scopeFactory;

    public Worker(ILogger<Worker> logger, IServiceScopeFactory scopeFactory, IHostApplicationLifetime hostApplicationLifeTime)
    {
        _logger = logger;
        _scopeFactory = scopeFactory;
    }

    public override Task StartAsync(CancellationToken cancellationToken)
    {
        return base.StartAsync(cancellationToken);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            //Running task
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error");
        }            
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Worker stopped at: {DateTime.Now}");
        base.StopAsync(cancellationToken);
        return Task.CompletedTask;
    }

    public override void Dispose()
    {
        _logger.LogInformation($"Worker disposed at: {DateTime.Now}");

        base.Dispose();
    }
}

关于这个的文档不多

您的代码已经接受 IHostApplicationLifetime 作为其第三项服务。您可以在希望主机终止时调用 StopApplication()

尽管 StopAsync 方法很危险 - 它表示服务已停止,即使 base `StopAsync 尚未停止。 That's the method 这将发出服务的取消令牌信号,因此这可能会产生意想不到的后果。应该改为:

public override Task StopAsync(CancellationToken cancellationToken)
{
    _logger.LogInformation($"Worker stopped at: {DateTime.Now}");
    return base.StopAsync(cancellationToken);
}

或者,更好的是:

public override Task StopAsync(CancellationToken cancellationToken)
{
    await base.StopAsync(cancellationToken);
    _logger.LogInformation($"Worker stopped at: {DateTime.Now}");
}

cancellationToken 参数在关闭期限到期并且需要立即终止服务时发出信号。它不被 BackgroundService 本身使用,它被传递给覆盖 StopAsync 实现