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

时间:2019-03-24 12:47:48

标签: javascript node.js typescript nestjs

Repo可在此处突出显示该问题。

我的比赛条件有问题。我创建了一个ConfigModule-它有一个forRoot和一个forChild

forRoot设置了.env文件的加载,而forChild在另一个模块中使用它。

问题是forChildforRoot之前被调用。 ConfigService将被注入缺少的配置,因为forRoot未被首先执行。

> AppModule > ConfigModule.forRoot InstanceModule >
> ConfigModule.forChild

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

I am in Config Module  FOR CHILD
I am in Config Module  FOR ROOT

如您所见,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

这是因为我检查了一些process.env是否可用,并已通过dotenv加载。当然,由于没有首先执行forRoot,所以forChild返回了自己的ConfigService的新实例。

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

因此,基本上,forChild正在执行并在ConfigService之前返回自己的forRoot

要使其生效,如果您在InstanceModule内注释掉AppModule,则它将自动开始侦听并从环境变量返回端口号。

当然,因为InstanceModule使用forChild-存在竞争情况。

1 个答案:

答案 0 :(得分:0)

为什么这不起作用?

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

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


替代品

看看nestjs/typeorm软件包。它在后台创建了一个共享的TypeOrmCoreModule,该共享在TypeOrmModule.forRoot / TypeOrmModule.forChild创建的不同动态模块实例之间共享。为了使其同时共享和动态,必须将其设置为@Global。在您的情况下,由于forChild导入中没有任何配置,因此您只需将整个ConfigModule全局化,然后忽略forChild()导入,因为{{1} }仍然可以在全球范围内使用。

如果您不希望服务在全球范围内可用,则可以在启动过程之后初始化服务,例如使用ConfigService的{​​{1}}方法。