工人服务意外停止工作

时间:2020-06-24 08:38:59

标签: c# .net-core service-worker worker

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

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

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);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:5)

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

这听起来绝对是我的例外。默认情况下,the BackgroundService implementation will ignore any exceptions thrown from ExecuteAsync。如果ExecuteAsync中引发了异常,则将其忽略,该服务将停止运行。

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

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  _logger.LogInformation("Sender is starting");
  try
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      await Task.Delay(10000, stoppingToken);
      _logger.LogDebug("Worker running at: {time}", DateTimeOffset.Now);
      if (!stoppingToken.IsCancellationRequested)
        await SendPendingMessages();
    }
  }
  catch (Exception ex) when (stoppingToken.IsCancellationRequested)
  {
    _logger.LogInformation("Sender is stopping");
  }
  catch (Exception ex) when (!stoppingToken.IsCancellationRequested)
  {
    _logger.LogError(ex, "Sender had error");
  }
}

在相关说明中,如果您认为这是“关键”后台服务,那么您还想stop the application host when this service stops

private readonly ILogger<Worker> _logger;
private readonly IHostApplicationLifetime _hostApplicationLifetime;

public Worker(ILogger<Worker> logger, IHostApplicationLifetime hostApplicationLifetime)
{
  _logger = logger;
  _hostApplicationLifetime = hostApplicationLifetime;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  _logger.LogInformation("Sender is starting");
  try
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      await Task.Delay(10000, stoppingToken);
      _logger.LogDebug("Worker running at: {time}", DateTimeOffset.Now);
      if (!stoppingToken.IsCancellationRequested)
        await SendPendingMessages();
    }
  }
  catch (Exception ex) when (stoppingToken.IsCancellationRequested)
  {
    _logger.LogInformation("Sender is stopping");
  }
  catch (Exception ex) when (!stoppingToken.IsCancellationRequested)
  {
    _logger.LogError(ex, "Sender had error");
  }
  finally
  {
    _hostApplicationLifetime.StopApplication();
  }
}

答案 1 :(得分:2)

请注意该行

await Task.Delay(10000, stoppingToken);

当您触发取消令牌时,将抛出OperationCancelledException,这是未处理的。

还要确保LogError() LogDebug()有一个catch try块并且不能抛出自己,这也会破坏您的代码。

看不到其他有问题的东西。