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.74k stars 7.63k forks source link

TRANSIENT providers cannot be nested when in different modules #9071

Closed JustDoItSascha closed 2 years ago

JustDoItSascha commented 2 years ago

Is there an existing issue for this?

Current behavior

When I have two services which are both Scope.TRANSIENT and the services are in different modules, I get this error:

Error: 
    at Injector.loadInstance (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:41:19)
    at Injector.loadProvider (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:74:20)
    at Injector.resolveComponentHost (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:164:24)
    at Injector.resolveComponentInstance (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:158:21)
    at resolveParam (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:108:38)
    at async Promise.all (index 0)
    at Injector.resolveConstructorParams (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:123:27)
    at Injector.loadInstance (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:52:9)
    at Injector.loadProvider (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:74:9)
    at Injector.resolveComponentHost (/Users/.../Sites/nest-scope-test/node_modules/@nestjs/core/injector/injector.js:164:13)

Minimum reproduction code

https://stackblitz.com/edit/nestjs-typescript-starter-k5mqcg

Steps to reproduce

Tested with 8.2.6

@Injectable({
    scope: Scope.TRANSIENT,
})
export class App2Service {}

@Module({
    providers: [
        App2Service,
    ],
    exports: [
        App2Service,
    ]
})
export class App2Module {}

@Injectable({
    scope: Scope.TRANSIENT,
})
export class AppService {
    constructor(
        private app2: App2Service,
    ) {
    }
}

@Module({
    imports: [
        App2Module,
    ],
    controllers: [],
    providers: [AppService],
})
export class AppModule {
    constructor(
        private appService: AppService,
    ) {
    }
}

Expected behavior

That nest starts

Package

Other package

No response

NestJS version

8.2.6

Packages versions

{
  "name": "nest-scope-test",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@moio/moio-tcp-interface": "1.23.2",
    "@moio/shared-cloud": "1.2.15",
    "@nestjs/common": "^8.0.0",
    "@nestjs/config": "1.1.6",
    "@nestjs/core": "^8.0.0",
    "@nestjs/microservices": "8.2.6",
    "@nestjs/mongoose": "9.0.2",
    "@nestjs/platform-express": "^8.0.0",
    "mongoose": "6.1.8",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.2.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^8.0.0",
    "@nestjs/schematics": "^8.0.0",
    "@nestjs/testing": "^8.0.0",
    "@types/express": "^4.17.13",
    "@types/jest": "27.0.2",
    "@types/node": "^16.0.0",
    "@types/supertest": "^2.0.11",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0",
    "eslint": "^8.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "^27.2.5",
    "source-map-support": "^0.5.20",
    "supertest": "^6.1.3",
    "ts-jest": "^27.0.3",
    "ts-loader": "^9.2.3",
    "ts-node": "^10.0.0",
    "tsconfig-paths": "^3.10.1",
    "typescript": "^4.3.5"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Node.js version

16

In which operating systems have you tested?

Other

No response

JustDoItSascha commented 2 years ago

Maybe it's related to https://github.com/nestjs/nest/issues/8872

yitzchak-ben-ezra-ecoplant commented 2 years ago

@JustDoItSascha I really don't know if it's related.. but hear that: I just came to this issue through Google search. because I'm having the same issue. I saw your reference - and this second issue is an issue I created not a long time ago (and was closed without getting any help!)

so I don't know if it's related (because my current task is not regarding the logger - it's for upgrading nestjs from 7 to 8) but it might be..

EDIT: Ok, after getting a bit into-it I got remembered. my issue (#8872) was that PinoLogger was not acting like TRANSIENT - the first injection was ok, but the rest were same object! The key point here is that I used nestjs 7!! when updating to nestjs 8 - same project - it's getting to this crash you opened here. so yes - they are highly related!!

and I didn't got any help from this repo, nor PinoLogger repo, nor nestjs Discord [only there they approved it's a bug - but no one took ownership to solve it]

I hope it'll get solved...

yitzchak-ben-ezra-ecoplant commented 2 years ago

a reasonable workaround:

the issue is the inner Transient service cannot be found in outer module.. so if you add the Transient service to the providers list of the outer module - it'll work!! not the cleanest way - but helps to get forward.

@Injectable({ scope: Scope.TRANSIENT })
export class App2Service {}

@Module({
    providers: [App2Service],
    exports: [App2Service],
})
export class App2Module {}

@Injectable({ scope: Scope.TRANSIENT })
export class AppService {
    constructor(private app2: App2Service) {}
}

@Module({
    imports: [App2Module],
    providers: [AppService, App2Service], // <-- Workaround here - App2Service was added
})
export class AppModule {
    constructor(private appService: AppService) {}
}
kamilmysliwiec commented 2 years ago

Let's track this here https://github.com/nestjs/nest/pull/9322