Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NestJs using same instance of service in multiple modules

Tags:

nestjs

I have got a NestJs app, that uses two services. The DbService that connects to the Db and the SlowService that does stuff rather slow and uses the injected DbService.

Now the app shall provide health routes outside of the api base path, so i need a different module that provides the controllers for the health routes.

I created a base module.

import { Module } from '@nestjs/common'
import { SlowService } from './slow.service'
import { DbService } from './db.service'

@Module({
  imports: [],
  controllers: [],
  providers: [DbService, SlowService],
  exports: [DbService, SlowService]
})
export class BaseModule {
}

The ApiModule and the HealthModule now both import the base module to be able to use the services.

  imports: [BaseModule],

There is only a small problem. Both modules seem to construct their own instance of the service but I need it to be the same instance. I assume this, because the console.log from the constructor appear twice when starting the app. Am I missing a setting or something?

UPDATE

Here is my bootstrap method, so you can see how I initialize the modules.

async function bootstrap (): Promise<void> {
  const server = express()
  const api = await NestFactory.create(AppModule, server.application, { cors: true })
  api.setGlobalPrefix('api/v1')
  await api.init()
  const options = new DocumentBuilder()
    .setTitle('...')
    .setLicense('MIT', 'https://opensource.org/licenses/MIT')
    .build()
  const document = SwaggerModule.createDocument(api, options)
  server.use('/swaggerui', SwaggerUI.serve, SwaggerUI.setup(document))
  server.use('/swagger', (req: express.Request, res: express.Response, next?: express.NextFunction) => res.send(document))
  const health = await NestFactory.create(HealthModule, server.application, { cors: true })
  health.setGlobalPrefix('health')
  await health.init()
  http.createServer(server).listen(Number.parseInt(process.env.PORT || '8080', 10))
}
const p = bootstrap()

like image 283
Woozar Avatar asked Apr 24 '19 09:04

Woozar


People also ask

Are NestJS services Singleton?

NestJS Modules are Singletons by default. Their Providers are also singletons when they are provided from within the same module. However, there are cases where we want to use just a single solo class as a provider to a couple or more modules. In such cases, we can use the solo class as singleton or not.

What is @module in NestJS?

A module is a class annotated with a @Module() decorator. The @Module() decorator provides metadata that Nest makes use of to organize the application structure. Each application has at least one module, a root module.

What is NestJS forRoot?

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.


1 Answers

Maybe you defined the services as providers for 2 modules. What you need to do is only define your BaseModule as import in the module where you need it.

This example demonstrates the service OtherService in OtherModule which needs the DbService from BaseModule. If you run the example you will see that it only instantiates the DbService once.

import {Injectable, Module} from '@nestjs/common';
import {NestFactory} from '@nestjs/core';

@Injectable()
export class SlowService {
  constructor() {
    console.log(`Created SlowService`);
  }
}

@Injectable()
export class DbService {
  constructor() {
    console.log(`Created DbService`);
  }
}

@Module({
  imports: [],
  providers: [SlowService, DbService],
  exports: [SlowService, DbService]
})
export class BaseModule {}

@Injectable()
export class OtherService {
  constructor(private service: DbService) {
    console.log(`Created OtherService with dependency DbService`);
  }
}

@Module({
  imports: [BaseModule],
  providers: [OtherService],
})
export class OtherModule {}

@Module({
  imports: [
    BaseModule,
    OtherModule
  ],
})
export class AppModule {}

NestFactory.createApplicationContext(AppModule).then((app) => console.log('🥑 context created'));

This gist demonstrates BAD usage of providers, resulting in instantiating the DbService twice: https://gist.github.com/martijnvdbrug/12faf0fe0e1fc512c2a73fba9f31ca53

like image 98
MartijnvdB Avatar answered Dec 31 '22 09:12

MartijnvdB