nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.73k stars 7.63k forks source link

Add configuration phase before http/rpc/ws servers launched #86

Closed artaommahe closed 7 years ago

artaommahe commented 7 years ago

There is a case when microservice should get/request some configuration (or load initial data from db to memory storage) from separate config service before his servers( http/rpc/ws) will be launched. Would be cool to have an opportunity to delay nest servers launch providing some function that returns Observable. This function should has access to app services and http/rpc requests to get/load initial data. Also there is related issue - what if nest servers config (e.x. launch ports) should be requested from separate config service (http/rpc request). Currently it requires non-framework code that would wrap nest launch before configs loaded.

kamilmysliwiec commented 7 years ago

Hi @artaommahe,

Take a look - https://docs.nestjs.com/lazy-microservice-client.html. Is it something what are you looking for?

artaommahe commented 7 years ago

@kamilmysliwiec mmm i need to defer any server (http/ws) launch before init done. App should not be publicly available until it load all initial data/configuration params.

FranciZ commented 7 years ago

@artaommahe Did you figure anything out? Have been looking at the various aspects of initialisation and have yet to figure this one out.

@kamilmysliwiec It's pretty essential to be able to defer server startup until all outside dependencies like database connections and third party API integrations have been established. Is there any way to achieve this at the moment?

As an example of non Nest/Typescript init for one of my projects. I'd like to achieve this type of initialisation with Nest.

  postgres.connect()
  .then(raven.init)
  .then(s3.connect)
  .then(redis.connect)
  .then(bigQuery.connect)
  .then(server.init)
  .then((server) => require('./resources').init({ server, sync: true })
    .then(cron.init)
    .then(() => {

      server.get('*', (req, res) => ErrorHandler({ req, res }, 'Page not found', 404));

      // Catch any unhandled errors
      server.use((err, req, res, next) => {
        if (err) ErrorHandler({ req, res }, err, 500);
        else next();
      });
    })
  )
  .catch(err => {
    Logger.error(err);
    process.exit(1);
  });
artaommahe commented 7 years ago

@FranciZ nope, waiting for nest implementation )

cojack commented 7 years ago

@artaommahe will async onModuleInit functions cover your case?

https://docs.nestjs.com/lifecycle-events.html

artaommahe commented 7 years ago

@cojack it fires after servers init and does not delay microservice (his servers) starting. I cant allow microservice to be publicly available until it requested environment configs from another microservice (with important config data) and connected to database

cojack commented 7 years ago

@artaommahe I feel the same needs, and I would like to help in this case (because I miss them too) and thinking about the solution for this. Do you have any proposal of how the API, Interfaces of this might looks like for you? It might be a good start to collect a requirements and then start to improve the nest ;)

artaommahe commented 7 years ago

@cojack mb smth like onModuleInit in module constructor that returns observable and delays application bootstrap (servers run). I need to inject any service here, have a possibility to make RPC calls (RPC client should be available in servers) or WS requests (if someone use websocket for cross-services communication). Hm, looks like servers (at least WS) should be available here but dont available from outside for public requests? Becoming more complicated )

cojack commented 7 years ago

@artaommahe so I guess we're looking for async component initialization callback. Then the case we have, when fire this?

  1. After module init,
  2. After all of the modules init (deps resolution [@shared()])?

So, then we will add a special function, similar to the onModuleInit but fe like in angular and his components OnInit?

I would like to (receive / get) more suggestions from you and start discussing this subject to have a clear path of requirements. So please submit your suggestions. This concerns all of you.

cojack commented 7 years ago

@artaommahe please check PR

artaommahe commented 7 years ago

@cojack setupModules() is called after await this.callInitHook(); and due to do this

    public setupModules() {
        SocketModule.setup(this.container, this.config);
        MiddlewaresModule.setup(this.container, this.config);
        MicroservicesModule.setupClients(this.container);
    }

in onModuleInit RPC clients and WS calls will be unavailable

cojack commented 7 years ago

@artaommahe wasn't this expose RPC and WS on the world before the onModuleInit? I have to check this, fell free to update the commit/pr.

cojack commented 7 years ago

@artaommahe It expose the websocket to the world before rest of app is ready, so I don't think it's a good idea to move them after the setupModules call. Without it it won't fit your requirement?

kamilmysliwiec commented 7 years ago

Hey guys, In the nearest release it'd be possible to create an async components (factories & values). All components, which depends on async components, would be also async, so you can use them as a some kind of configuration phase.

{
     provide: 'AsyncDatabaseConnection',
     useFactory: async (...args): Promise<any> => {

     },
     inject: [...]
},

Those async components are just promises, which have to be resolved before http/rpc/ws servers launch and may be injected into another components.

kamilmysliwiec commented 7 years ago

Hi @artaommahe, A little bit more about async components is available here

bradleyayers commented 6 years ago

@kamilmysliwiec that link seems broken now

kamilmysliwiec commented 6 years ago

Update https://docs.nestjs.com/fundamentals/async-components ^

lock[bot] commented 5 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.