NestJS:在自定义模块中使用 forRoot / forChild - 竞争条件?

Ian*_*son 2 javascript node.js typescript nestjs

此处提供了Repo来突出显示该问题。

我遇到了竞争条件问题。我创建了一个ConfigModule- 这有一个forRoot和一个forChild

设置文件forRoot的加载.envforChild在另一个模块中使用它。

问题是forChild之前调用过forRoot。由于尚未首先执行,因此将ConfigService注入缺少的配置。forRoot

> AppModule > ConfigModule.forRoot InstanceModule >
> ConfigModule.forChild
Run Code Online (Sandbox Code Playgroud)

我放置了一些简单的console.log命令来输出这个

I am in Config Module  FOR CHILD
I am in Config Module  FOR ROOT
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,forChild首先执行的是,我尝试使用forwardRef,但没有成功。

如果你让应用程序运行你会看到

[2019-03-24T11:49:33.602] [ERROR] ConfigService - There are missing mandatory configuration: Missing PORT
[2019-03-24T11:49:33.602] [FATAL] ConfigService - Missing mandatory configuration, cannot continue!, exiting
Run Code Online (Sandbox Code Playgroud)

这是因为我检查了一些process.env可用的文件,这些文件是在 via 中加载的dotenv。当然,因为forRoot不会首先执行,所以forChild会返回它自己的新实例ConfigService

ConfigService验证环境变量的可用性。

所以,基本上, 是在 之前forChild执行并返回自己的。ConfigServiceforRoot

为了使其工作,如果您注释掉内部InstanceModuleAppModule那么它将自动开始侦听并从环境变量返回端口号。

当然,因为InstanceModule使用forChild- 存在竞争条件。

Kim*_*ern 6

为什么这不起作用?

1)Nest建立一个依赖图并根据该图实例化给定的模块及其提供者。导入的顺序或动态模块方法的命名 ( forRoot/ forChild) 不会影响实例化的顺序。

2)当您创建动态模块时,每个模块将是它自己的实例,它们不会像常规模块那样是单例。在您的情况下,您将创建两个不同的ConfigModule实例,并使用它创建两个不同的ConfigService实例;因此他们不会共享您的.env配置。这是行不通的,与实例化顺序无关。


备择方案

看看nestjs/typeorm包装。在底层,它创建一个共享,它在/TypeOrmCoreModule创建的不同动态模块实例之间共享。为了使其能够同时共享和动态,它必须被制作出来。在您的情况下,由于您的导入中没有任何配置,因此您只需将整个全局化,然后省略导入,因为无论如何它们都是全局可用的。TypeOrmModule.forRootTypeOrmModule.forChild@GlobalforChildConfigModuleforChild()ConfigService

如果您不希望您的服务全局可用,您可以在启动过程后初始化您的服务,例如在您的AppModule方法中onModuleInit