#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 — теперь это намного понятнее.