NestJS 提供者需要无状态吗?

bob*_*ght 2 spring nestjs

我是一名长期学习 NestJS 的 Spring 开发人员。这些相似之处是如此惊人,我很喜欢这让我变得高效。然而,一些文档让我对一件事感到困惑。

我尝试将 Nest“提供者”比作具有默认范围的 Spring beans。例如,我创建 @Injectable 服务类,并将它们视为类似于 Spring @Services。因此,我假设这些服务类需要是线程安全的 - 无状态等。但是,这里的 Nest 文档对我来说有点含糊,有点暗示这可能没有必要(强调我的):

对于来自不同编程语言背景的人来说,可能会意外地发现,在 Nest 中,几乎所有内容都在传入请求之间共享。我们有一个到数据库的连接池、具有全局状态的单例服务等。请记住,Node.js 不遵循请求/响应多线程无状态模型,在该模型中,每个请求都由单独的线程处理。因此,使用单例实例对于我们的应用程序来说是完全安全的。

如果单个请求不在自己的线程中处理,那么 Nest 提供程序可以包含可变状态吗?应用程序需要确保每个传入请求都以“干净的状态”开始 - 例如,使用 NestInterceptor 初始化该状态。但对我来说,该文档显示提供程序是作为单例创建的,因此可以用作类似于数据包装容器的东西,就像 Java 中的 ThreadLocal 一样。

我是否读错了,或者这是 Nest 和 Spring 之间的行为差​​异?

Ale*_*yne 5

您确实应该使请求处理无状态。

我对 Spring 一无所知,但在 NestJS(以及一般的异步 JavaScript)中,它是单线程的,但不会阻塞 I/O。这意味着同一服务实例的同一线程可以同时处理多个请求。它一次只能做一件事,但它可以在前一件事等待数据库查询时开始做下一件事,或者等待请求完成传输,或者等待外部服务响应,或者等待文件系统传递文件的内容等

因此,在一个线程中,对于一个服务的一个实例,可能会发生这种情况:

  • 请求 A 进来。
  • 为请求 A 调度数据库查询。
  • 请求 B 进来。
  • 为请求 B 调度数据库查询。
  • 请求 A 的数据库查询返回,并发送响应。
  • 请求 B 的数据库查询返回,并发送响应。

这对于状态意味着它将在请求之间共享。如果您的服务在异步操作的一个步骤中设置实例属性,则另一个异步操作可能会在第一个异步操作完成之前启动,并为该实例属性设置一个新值,这可能不是您想要的。

我相信 Nest 文档提到的“全局状态”不是每个请求,而是一般配置状态。例如外部服务的 URL 或数据库的凭据。


还值得一提的是,控制器接收一个请求对象,它代表该特定请求。向该请求对象添加属性是很常见的,例如当前经过身份验证的用户。可以传递请求对象,以对该架构友好的方式提供控制器和服务上下文。