-
-
Notifications
You must be signed in to change notification settings - Fork 7.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dependency injection not resolving to the correct singleton instance #11550
Comments
I agree. In nestjs, DI (Dependency Injection) is performed based on the type of the arguments, regardless of the order of the arguments. Therefore, even if you change the order of receiving AService and IDatabaseProvider arguments in the BService class constructor, DI should be performed correctly (AService must be a singleton). However, after checking mini reproduction, I am experiencing the same problem in my development environment. @Injectable()
export class BService extends BaseEntityService {
constructor(
public aService: AService,
@Inject(DATABASE_PROVIDER) public database: IDatabaseProvider,
) {
super(database);
}
} import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { AService } from './modules/entities/a/a.service';
import { BService } from './modules/entities/b/b.service';
import { CService } from './modules/entities/c/c.service';
import { PlainLogger } from './plain-logger';
const logger = new PlainLogger('AppController');
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
private readonly aService: AService,
private readonly bService: BService,
private readonly cService: CService,
) {
logger.warn(
`Is ${AService.name} instance the ${AService.name} singleton instance?
${BService.name}: ${this.aService === this.bService.aService}
${CService.name}: ${this.aService === this.cService.aService}`,
);
}
@Get()
getHello(): string {
return this.appService.getHello();
}
} In the code above, the I also think this is different from the principles of nestjs we know. |
Not sure if I'm following. To better understand what's happening in your code, you can add the console.log in the Then you'll realize that you're actually injecting 2 DATABASE_PROVIDER providers: And the reason is that explicit Your If you use the explicit syntax instead, as follows: Everything will work as expected |
And what in this logic changes the order of dependencies in @Injectable()
export class BService extends BaseEntityService {
constructor(
@Inject(DATABASE_PROVIDER) public database: IDatabaseProvider,
public aService: AService,
) {
super(database);
}
} |
Because then the explicit injection array is [DATABASE_PROVIDER] (note: no [1] element) since the explicitly injected element is at the same position in the constructor arguments array as in the extended BaseEntityService [DATABASE_PROVIDER] = [DATABASE_PROVIDER] while: BaseEntityService [DATABASE_PROVIDER] = [DATABASE_PROVIDER, DATABASE_PROVIDER] |
Incredible logic! @kamilmysliwiec, do you really think that there is nothing to change in this case? |
There's actually another issue related to this problem #2581 I know that the current behavior might not be immediately obvious and so as I've mentioned here #2581 (comment) - PRs are more than welcome! |
@kamilmysliwiec Ahaa! So the issue is the result of constructor dependencies being declared in a different order in the subclass along with the explicit |
In fact, this is an obvious bug, it is not a feature. And the fact that this issue is closed without fixing this bug is a bad practice. |
I guess this was closed in favor of issue #2581 |
#2581 is related to this issue, it's not duplicate of this issue. |
so you're saying that by fixing that one we wouldn't fix this one too, right? |
I don't known. Personally, I don't see any relation between #2581 and this issue at all. |
I think we can trust the author of the code then 😄 |
Unfortunately, I've had the experience of @kamilmysliwiec closing an issue with a bug without actually closing the bug itself. Moreover, this bug related to the security module. So I have reason to assume that closing #2581 may or may not close this issue. |
Is there an existing issue for this?
Current behavior
The dependencies declaration order in a service's constructor causes the service to receive a private instance of a depended service instead of the singleton service exported in the corresponding module. It also alters the instantiation order, causing the dependant service to be instantiated before the depended service.
Example
Logs
Minimum reproduction code
https://github.com/capelski/nest-dependency-injection-issue
Steps to reproduce
npm ci
npm run start:dev
Expected behavior
The dependencies declaration order in a service's constructor doesn't alter the instantiation of the app singleton services.
Package
@nestjs/common
@nestjs/core
@nestjs/microservices
@nestjs/platform-express
@nestjs/platform-fastify
@nestjs/platform-socket.io
@nestjs/platform-ws
@nestjs/testing
@nestjs/websockets
Other package
No response
NestJS version
9.0.0
Packages versions
[System Information]
OS Version : macOS Unknown
NodeJS Version : v18.13.0
NPM Version : 8.19.3
[Nest CLI]
Nest CLI Version : 9.0.0
[Nest Platform Information]
platform-express version : 9.0.0
schematics version : 9.0.0
testing version : 9.0.0
common version : 9.0.0
core version : 9.0.0
cli version : 9.0.0
Node.js version
18.13.0
In which operating systems have you tested?
Other
No response
The text was updated successfully, but these errors were encountered: