问题描述
我已经建立了一个非常简单的工作服务项目,只有一个工作人员(目前)。下面是 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 仍然无法理解。