工人服务意外停止工作

Aut*_*zer 4 c# worker service-worker .net-core

我有 .NET Core 3+ 工作服务,它每 10 秒检查一次“一些东西”。有一次,它“随机”停止这样做,我不知道为什么。到目前为止它发生了两次并且没有异常日志或类似的东西,所以我只能假设我应该在try-catch内部添加一个ExecuteAsync,但我的问题是:是否有任何已知问题可能导致类似的行为,工作人员刚刚停止执行?

是的,没有请求取消(否则,我想它会记录消息“发件人正在停止”)。

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

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Sender is starting");
        stoppingToken.Register(() => _logger.LogInformation("Sender is stopping"));

        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(10000, stoppingToken);

            _logger.LogDebug("Worker running at: {time}", DateTimeOffset.Now);

            if (!stoppingToken.IsCancellationRequested)
                await SendPendingMessages();
        }
    }

    private async Task SendPendingMessages()
    {
        var list = ...

        foreach (var item in list)
        {
            try
            {
                // Do stuff as expected
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 8

到目前为止它发生了两次并且没有异常日志或类似的东西,所以我只能假设我应该在 ExecuteAsync 中添加一个 try-catch,但我的问题是:是否有任何已知问题可能导致类似的行为工人只是停止执行?

这对我来说绝对是个例外。默认情况下,BackgroundService实现将忽略来自抛出的异常ExecuteAsync。如果从 引发异常ExecuteAsync,则忽略该异常并且服务将停止运行。

我总是建议使用顶级try/catch日志记录,以便您至少知道会发生这种情况:

受保护的覆盖异步任务 ExecuteAsync(CancellationTokentoppingToken)
{
  _logger.LogInformation("发件人正在启动");
  尝试
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      等待任务。延迟(10000,停止令牌);
      _logger.LogDebug("Worker 运行时间:{time}", DateTimeOffset.Now);
      if (!stoppingToken.IsCancellationRequested)
        等待 SendPendingMessages();
    }
  }
  catch (Exception ex) when (stoppingToken.IsCancellationRequested)
  {
    _logger.LogInformation("发件人正在停止");
  }
  catch (Exception ex) when (!stoppingToken.IsCancellationRequested)
  {
    _logger.LogError(ex, "发件人有错误");
  }
}

在相关说明中,如果这是您认为的“关键”后台服务,那么您还希望在此服务停止时停止应用程序主机

私有只读 ILogger<Worker> _logger;
私有只读 IHostApplicationLifetime _hostApplicationLifetime;

公共工作者(ILogger<Worker> 记录器,IHostApplicationLifetime hostApplicationLifetime)
{
  _logger = 记录器;
  _hostApplicationLifetime = hostApplicationLifetime;
}

受保护的覆盖异步任务 ExecuteAsync(CancellationTokentoppingToken)
{
  _logger.LogInformation("发件人正在启动");
  尝试
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      等待任务。延迟(10000,停止令牌);
      _logger.LogDebug("Worker 运行时间:{time}", DateTimeOffset.Now);
      if (!stoppingToken.IsCancellationRequested)
        等待 SendPendingMessages();
    }
  }
  catch (Exception ex) when (stoppingToken.IsCancellationRequested)
  {
    _logger.LogInformation("发件人正在停止");
  }
  catch (Exception ex) when (!stoppingToken.IsCancellationRequested)
  {
    _logger.LogError(ex, "发件人有错误");
  }
  最后
  {
    _hostApplicationLifetime.StopApplication();
  }
}