最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - NestJS: Using forRootforChild in custom module - race condition? - Stack Overflow

programmeradmin1浏览0评论

Repo is available here to highlight the issue.

I am having a problem with a race condition. I have created a ConfigModule - this has a forRoot and a forChild.

The forRoot sets up the loading of the .env file and the forChild uses it in another module.

The problem is that forChild is called before forRoot. The ConfigService would be injected with missing config because forRoot hasn't executed first.

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

I placed some simple console.log mands that output this

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

As you can see the forChild is being executed first, I tried using forwardRef and that didn't work.

If you let the application run you will see

[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

This is because I check that some process.env are available which are loaded in via dotenv. Of course, because the forRoot isn't executed first then the forChild returns its own new instance of the ConfigService.

ConfigService validates the availability of the environment variables.

So, basically, the forChild is executing and returning its own ConfigService before forRoot.

TO make it work, if you ment out the InstanceModule inside the AppModule then it will automatically start listening and returns the port number from an environment variable.

Of course, because InstanceModule uses the forChild - there is a race condition.

Repo is available here to highlight the issue.

I am having a problem with a race condition. I have created a ConfigModule - this has a forRoot and a forChild.

The forRoot sets up the loading of the .env file and the forChild uses it in another module.

The problem is that forChild is called before forRoot. The ConfigService would be injected with missing config because forRoot hasn't executed first.

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

I placed some simple console.log mands that output this

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

As you can see the forChild is being executed first, I tried using forwardRef and that didn't work.

If you let the application run you will see

[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

This is because I check that some process.env are available which are loaded in via dotenv. Of course, because the forRoot isn't executed first then the forChild returns its own new instance of the ConfigService.

ConfigService validates the availability of the environment variables.

So, basically, the forChild is executing and returning its own ConfigService before forRoot.

TO make it work, if you ment out the InstanceModule inside the AppModule then it will automatically start listening and returns the port number from an environment variable.

Of course, because InstanceModule uses the forChild - there is a race condition.

Share Improve this question edited Mar 24, 2019 at 16:58 Kim Kern 60.6k20 gold badges217 silver badges214 bronze badges asked Mar 24, 2019 at 12:47 Ian GregsonIan Gregson 4276 silver badges16 bronze badges 2
  • Can you post the link to your repo? – Kim Kern Commented Mar 24, 2019 at 12:56
  • 1 Sorry my bad, I forgot to paste it :-) Updated it now. – Ian Gregson Commented Mar 24, 2019 at 12:58
Add a ment  | 

1 Answer 1

Reset to default 8

Why does this not work?

1) Nest builds up a dependency graph and instantiates the given modules and their providers according to this graph. The order of your imports or the naming of your dynamic modules's methods (forRoot/forChild) does not influence the order of the instantiation.

2) When you create dynamic modules, each module will be its own instance, they won't be singletons like regular modules. In your case, you'd create two different ConfigModule instances and with it, two different ConfigService instances; hence they won't share your .env configuration. This can't work, independent of the instantiation order.


Alternatives

Have a look at the nestjs/typeorm package. Under the hood, it creates a shared TypeOrmCoreModule, which is shared between the different dynamic module instances created by TypeOrmModule.forRoot / TypeOrmModule.forChild. For it to be shared and dynamic at the same time, it has to be made @Global though. In your case, since you don't have any configurations in your forChild imports, you would just make the whole ConfigModule global and then omit the forChild() imports, since the ConfigService would be globally available anyway.

If you don't want your service to be globally available, you could initialize your service after the startup process, for example in your AppModule's onModuleInit method.

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>