近日,多个开发者社区和 GitHub Issue 区相继报告了一个影响 ASP.NET Core 10 预览版的严重问题:当应用程序使用 Scoped(作用域)生命周期 的 RabbitMQ 连接时,部分消息请求会随机出现“永久挂起”现象,导致服务吞吐量骤降,甚至引发级联超时。该问题已在 .NET 官方仓库中标记为 high-priority bug,引发广泛关注。

问题复现:看似正常的代码却暗藏陷阱

据最早报告的开发者描述,其团队在最新的 .NET 10 预览版中构建微服务架构,采用标准的 RabbitMQ.Client 库进行消息发布和消费。为了遵循依赖注入(DI)的最佳实践,他们将 IConnectionIModel 注册为 Scoped 生命周期,期望每个 HTTP 请求或消息处理管道中获取独立的连接实例。

代码示例大致如下:

services.AddScoped<IConnection>(sp => {
    var factory = new ConnectionFactory { HostName = "localhost" };
    return factory.CreateConnection();
});
services.AddScoped<IModel>(sp => {
    var connection = sp.GetRequiredService<IConnection>();
    return connection.CreateModel();
});

这种模式在前几个 .NET 版本中被广泛使用,但在 .NET 10 中却频繁导致 channel 级别的阻塞。具体表现为:部分请求成功发布消息,而另一部分请求则永远卡在 IModel.BasicPublishQueueDeclare 调用上,既不抛异常也不超时,直到应用程序重启或连接被强制关闭。

深度排查:为何 Scoped 模式成为元凶?

社区多位贡献者通过 dump 分析和网络抓包,初步锁定了问题根源——连接复用冲突与资源回收时序异常。在 Scoped 模式下,IConnection 的生命周期由 DI 容器管理,请求结束后容器会尝试释放该连接。但 RabbitMQ 客户端的内部心跳线程、自动恢复机制与 ASP.NET Core 的请求结束回调存在 竞态条件,导致以下两种典型场景:

  1. 心跳线程争夺:当容器释放连接时,若恰好有未完成的心跳确认(Heartbeat ACK),RabbitMQ 服务端会认为连接异常,将 channel 标记为“blocked”状态,后续所有请求的 channel 操作被无限等待。
  2. 自动恢复与池化冲突:RabbitMQ.Client 6.x 版本内置了自动恢复机制,而 Scoped 模式下每次请求都会创建新的物理连接,这些连接在恢复过程中与容器析构函数产生死锁,导致线程池线程被耗尽。

更棘手的是,该问题具有随机性——在低负载测试中几乎无法复现,只有当并发请求数超过一定阈值(约 50 个并发)时才会暴露,且不同环境下的触发概率差异很大。

官方回应与临时方案

微软 .NET 团队在 GitHub Issue #102443 中确认了该问题,并指出问题可能涉及 RabbitMQ.Client 库与 ASP.NET Core 10 请求管道之间的底层同步机制变化。由于 .NET 10 仍在预览阶段,团队正在与 RabbitMQ 客户端维护者联合修复,预计在下一个预览版(Preview 3)中合入补丁。

针对急需上线的开发团队,社区提供了三种临时解决方案:

  • 方案一:使用 Singleton 生命周期。将 IConnection 注册为单例,由应用程序手动管理连接生命周期,避免 DI 容器介入资源回收。
  • 方案二:禁用自动恢复。在创建 ConnectionFactory 时设置 AutomaticRecoveryEnabled = false,并自行实现重试逻辑。
  • 方案三:升级至 RabbitMQ.Client 7.0.0-rc(当前为候选版本),该版本已针对 .NET 10 进行了新的生命周期适配,但尚未经过大规模验证。

影响评估与行业警示

此次 Bug 影响范围主要集中在 采用 .NET 10 预览版进行架构升级的团队,以及 错误将 RabbitMQ 连接沿用旧版 DI 最佳实践 的开发者。值得注意的是,该问题不会出现在使用 Singleton 连接或非 DI 手动管理的项目中。

业内人士指出,这折射出 .NET 生态演进中的经典矛盾:微服务框架不断强化 DI 规范化,但中间件客户端的生命周期管理却未能同步进化。RabbitMQ、Redis、MongoDB 等第三方连接库往往假定连接为重量级对象,而 Scoped 模式却试图将其“轻量化”,本质上是设计理念的冲突。

目前,GitHub 上已有超过 380 名开发者订阅了该 Issue,评论区中不乏“回退到 .NET 8 以规避风险”的声音。建议在生产环境中使用 .NET 10 预览版的企业 暂缓 RabbitMQ 相关的微服务迁移,等待官方修复后再做升级计划。对于正在验证新特性的团队,请务必采用上述临时方案,并加入消息超时熔断机制,以防止进程卡死导致雪崩。

我们将持续跟踪该 Bug 的修复进展,并在第一时间带来后续报道。