使用异步时,工作服务进程无缘无故停止

问题描述

我已经建立了一个非常简单的工作服务项目,只有一个工作人员(目前)。下面是 ExecuteAsync 方法的完整代码

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  try
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      _logger.Loginformation("Worker running at: {time}",DateTimeOffset.Now);
      var engine = new CrawlerEngine(_logger);
      try
      {
        await engine.CrawlAsync(stoppingToken);
      }
      catch (Exception ex)
      {
        _logger.LogError(ex.ToString());
      }
      await Task.Delay(TimeSpan.FromMinutes(1));
    }
    _logger.Loginformation("Worker stopping at: {time}",DateTimeOffset.Now);
  }
  catch (Exception ex)
  {
    _logger.LogError(ex.ToString());
  }
}

如您所见,它相当简单,只是一个无限循环直到取消,其中唯一真正的逻辑都包含在 CrawlerEngine 中。

这里有一个问题,如果我运行该服务,它可能会运行几分钟然后退出。它不会记录“工人停止”或异常,它只是简单地停止整个过程。

我尝试更改 CrawlAsync 中的所有异步代码,因此它是完全同步的。这消除了问题,让我感到困惑。

我在 CrawlAsync 中的每个 Async 方法都返回 Task 或 Task 并等待。

所以我想也许一些异步代码抛出了一个没有被 try-catch 捕获的异常,但是据我所知,这个异常应该“冒泡”并被捕获,只要你'重新使用等待。

我什至添加一个 AppDomain.UnhandledException 处理程序,它也没有捕获任何内容

你知道这里发生了什么吗?

编辑:为了澄清起见,我想问一下异步是否有任何隐藏的细节,这会导致整个进程崩溃,而没有多少 try-catch 能够看到它?

编辑 2:似乎使我的进程崩溃的是 WebClient.DownloadStringAsTaskAsync 和 HttpClient.GetStringAsync。每当我使用任何一个时,我的进程都会在某个时候退出。使用同步方法下载字符串不会导致这种情况。

解决方法

我终于弄清楚退出进程的原因:StackOverflowException。

这解释了缺乏日志记录等。 我通过将递归方法(称为 HttpClient.GetStringAsync)更改为 for 循环来解决它。

为什么在使用 GetString 的非异步变体时它没有抛出 StackOverflow 仍然无法理解。