ASP.NET.核心集成福利彩票中奖规则死锁的奇怪情况

福利彩票中奖规则ASP.NET核心应用的常见方法之一是使用集成福利彩票中奖规则通过这一点获得Microsoft.aspnetCore.Testhost.testhost.testhost.包裹。特别是,可以使用最常常见的场景是通过的MVC应用程序的集成福利彩票中奖规则microsoft.aspnetcore.mvc.testing.,它为福利彩票中奖规则主机的顶部提供了一组MVC特定的帮助程序。

在这篇文章中,我想在ASP.NET核心3.1应用程序中分享一个致命的死锁集成福利彩票中奖规则的情况。

集成福利彩票中奖规则

福利彩票中奖规则主机包提供的功能不是新的–自ASP.NET Web API天以来,这样的功能是ASP.NET应用程序横向的一部分。实际上我博客关于这个话题已经回到2012年,其中在内存中运行整个服务器 - 客户端管道是一个真正的新奇。

简而言之,该功能允许您使用常规应用程序引导路径启动应用程序服务器–您的完整主机配置,整个启动类,包括DI容器和所有中间件组件–但是,它不是在特定端口上启动HTTP侦听器,它仅初始化应用程序流水线内存中。然后是httpclient.,通过它ClientHandler.可以插入福利彩票中奖规则主机,使您能够通过应用程序通信httpclient.,使用典型的http抽象–好像您正在调用真正的直播服务器。

结果是,您可以为应用程序执行端到端的集成福利彩票中奖规则,而无需为您的应用启动真实的HTTP侦听器进程。这是一个很好的功能,并且已成为ASP.NET的主食,并且最近,ASP.NET核心应用程序开发。这官方文档页面有关如何在需要更多信息时,有关如何开始的信息非常详尽的信息。

死锁福利彩票中奖规则

我们在我们的工作中使用这些类型的集成福利彩票中奖规则,并在某些时候注意到我们注意到的一件事,即在某些负载级别–当有很多复杂的福利彩票中奖规则时,我们开始在福利彩票中奖规则中挂起(死锁)。这将永远不会发生在强大的驱动机器上,但只在CI运行期间,我们的案例中的码头图像是具有非常有限的资源。

我们使用的代码非常复杂,但它没有't做任何特别令人令人遗憾的是跳出来的潜在罪魁祸首。简化的代码变体如下:

所有这一切当然不会偏离如何使用它的方式–如在我之前链接的文档中制定的那样。它使用了WebApplicationFactory.,这是一部分microsoft.aspnetcore.mvc.testing.。该软件包包装福利彩票中奖规则主机,集成福利彩票中奖规则管道的所有核心逻辑都是部分 microsoft.aspnetcore.testhost.testserver.testhostserver.班级。

所以发生了什么事?

当然,历史上,反应反应,第一个想法,在asp.net中处理死锁时,一直思考,我们必须在某处有一个同步超越异步–必须有一些代码块在异步操作上块,最有可能是罪魁祸首。

然而.NET核心不再同步上下文了!换句话说,在ASP.NET核心在异步操作恢复时,来自线程池中的线程执行继续。这是所有的了“context-free”并且没有任何东西可以僵局了。所以这不应该是问题不再,对吧?但是,如果我们运行常规的核心应用程序,那将是真的。在这种情况下,我们正在运行集成福利彩票中奖规则,更具体地说是xunit.net福利彩票中奖规则。事实证明,XUNIT.NET使用自定义同步上下文,并且它有两个原因–强制执行其并行化限制,并在福利彩票中奖规则方法中支持异步void。

这让我们(Lukasz.做了一些伟大的侦探工作)来怀疑我们实际上可能会在毕竟某处与异步同步。和lo和看哪,它被发现了–但不是在我们的代码中,而是在框架本身。这testserver构造函数明确阻止异步操作:

因此,在您自己的代码库中没有任何错误,如果运行福利彩票中奖规则的机器具有单个CPU(例如低资源CI代理,或者是小型本地Docker Image),则将运行到XUnit福利彩票中奖规则死锁中。值得注意的是,这种同步逾越同步testserver仍然没有't已修复或在ASP.NET 6.0预览3中解决。在我们的情况下,WebApplicationFactory.一旦创建客户端,最终会超过同步路径。

在一个懒惰更强大的机器上,代码可以根据同时执行的福利彩票中奖规则量来生成非确定性死锁,xunit默认情况下并行化福利彩票中奖规则集合。

有几种方法。一个是设置并行线程的无限值。这可以完成xunit.runner.json.:

或作为属性:

我们选择选择的不同解决方案,这需要子类化WebApplicationFactory.,只需在XUnit同步上下文之外移动主机初始化,允许任务及其继续在任何其他线程上执行:

这里仍然存在同步异步,但不再涉及XUnit同步上下文。但当然,理想情况下,这将在ASP.NET核心福利彩票中奖规则主机中修复。