NestJS: использование forRoot / forChild в пользовательском модуле — условие гонки?

#javascript #node.js #typescript #nestjs

#javascript #node.js #typescript #nestjs

Вопрос:

Здесь доступно репозиторий, чтобы осветить проблему.

У меня проблема с состоянием гонки. Я создал ConfigModule — у этого есть forRoot и forChild .

forRoot Настраивает загрузку .env файла и forChild использует его в другом модуле.

Проблема в том, что forChild вызывается раньше forRoot . 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. Можете ли вы опубликовать ссылку на свой репозиторий?

2. Извините, я забыл вставить это 🙂 Обновил его сейчас.

Ответ №1:

Почему это не работает?

1) Nest создает граф зависимостей и создает экземпляры заданных модулей и их поставщиков в соответствии с этим графиком. Порядок вашего импорта или именование методов ваших динамических модулей ( forRoot / forChild ) не влияет на порядок создания экземпляра.

2) При создании динамических модулей каждый модуль будет отдельным экземпляром, они не будут одиночными, как обычные модули. В вашем случае вы бы создали два разных ConfigModule экземпляра, а вместе с ним и два разных ConfigService экземпляра; следовательно, они не будут совместно использовать вашу .env конфигурацию. Это не может работать независимо от порядка создания экземпляра.


Альтернативы

Взгляните на nestjs/typeorm пакет. Под капотом он создает общий TypeOrmCoreModule доступ, который используется совместно между различными экземплярами динамического модуля, созданными TypeOrmModule.forRoot / TypeOrmModule.forChild . Однако для того, чтобы он был общим и динамическим одновременно, его необходимо создать @Global . В вашем случае, поскольку у вас нет никаких конфигураций в вашем forChild импорте, вы бы просто сделали весь ConfigModule глобальный, а затем опустили forChild() импорт, поскольку ConfigService он в любом случае был бы доступен глобально.

Если вы не хотите, чтобы ваш сервис был доступен глобально, вы могли бы инициализировать свой сервис после процесса запуска, например, в вашем AppModule методе onModuleInit .

Комментарии:

1. Отличное объяснение, я протестировал его, и оно работает. И спасибо за объяснение forRoot и forChild — теперь это намного понятнее.