Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Service that acts as a singleton with NestJS

I am trying to create a Module that provdies a singleton service. Imagine a QueueService, simplest implementation would be a singleton service.

Reproducible repository: https://github.com/colthreepv/nestjs-singletons

WALL OF CODE

app.module.ts:

@Module({ imports: [FirstConsumerModule, SecondConsumerModule] })
export class AppModule {}

firstconsumer.module.ts and secondconsumer.module.ts (they are identical):

@Injectable()
class FirstConsumer {
  constructor(private readonly dependency: DependencyService) {}
}

@Module({
  imports: [DependencyServiceModule],
  providers: [DependencyService, FirstConsumer]
})
export class FirstConsumerModule {
  constructor(private readonly first: FirstConsumer) {}
}

dependency.module.ts:

@Injectable()
export class DependencyService {
  constructor() { console.log("Instance created") }
}

@Module({ providers: [DependencyService], exports: [DependencyService] })
export class DependencyServiceModule {}

CODE DONE

What I would like to obtain is having console.log Instance created just be posted once.
At the moment:

[NestFactory] Starting Nest application...
Instance created
Instance created
Instance created
[InstanceLoader] AppModule dependencies initialized +16ms
[InstanceLoader] DependencyServiceModule dependencies initialized +1ms
[InstanceLoader] FirstConsumerModule dependencies initialized +1ms
[InstanceLoader] SecondConsumerModule dependencies initialized +1ms
[NestApplication] Nest application successfully started +8ms
like image 559
Valerio Avatar asked Feb 12 '20 16:02

Valerio


1 Answers

In NestJS modules are the singletons and their providers are made to be singletons so long as they are provided from the same module. In your sample code you have your DependencyService in three different providers arrays for three different modules. What should be done instead is to only have it in the providers array of the DependencyServiceModule and the exports array as well. Then you only need to have the DependencyServiceModule in the imports array of the FrstConsumerModule and SecondConsumerModule and do not add the DependencyService to the providers array of either. Thanks to the being in the exports array, the provider is available to the module context already.

@Module({
  providers: [DependencyService],
  exports: [DependencyService]
})
export class DependencyServiceModule {}
@Module({
  imports: [DependencyServiceModule],
  providers: [FirstConsumer] // notice no DependencyService class
})
export class FirstConsumerModule {}
@Module({
  imports: [DependnecyServiceModule, FirstCosnumerModule]
})
export class AppModule {}

And with the above you'll only see one log of "Instance created" instead of two.

like image 89
Jay McDoniel Avatar answered Sep 30 '22 15:09

Jay McDoniel