Server/NodeJS & NestJS

NestJS) 의존성주입에서 객체 초기화 문제

Juzdalua 2025. 8. 6. 18:47

먼저 백그라운드를 정해본다.

 

1. AppModule에 임포트 순서대로 모듈의 초기화가 진행된다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import {
  EnvConfigModule,
  TypeOrmConfigService,
} from './config';

import { AuthModule } from './modules/auth/auth.module';
import { AdminModule } from './modules/admin/admin.module';

@Module({
  imports: [
    EnvConfigModule, // 환경변수를 생성해야하므로 가장 처음에 위치해야한다.
    AuthModule, // 2번째로 초기화
    AdminModule, // 3번째로 초기화
    TypeOrmModule.forRootAsync({ useClass: TypeOrmConfigService }), // webpack 실행시 entities 참조를 위해 데이터베이스 엔티티 모듈들 아래에 위치해야한다.
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule  {}

 

2. main.ts에 작성하면 AppModule 초기화 이전, 의존성 주입 전에 먼저 실행할 수 있다.

 

3. 서로 의존성을 주입하는 모듈의 경우, forwadRef를 통한 순환참조 문제를 해결할 수 있다.

 

4. NestJS의 의존성주입은 다음 순서로 이루어진다.

  • 모듈 객체 생성 
  • 생성자 콜 + 각 모듈의 provider에 명시된 객체들만 의존성 주입 (동시에 발생)
  • OnModuleInit 실행

 


전제상황

1. DB에 접근하여 CommonCode 파일을 불러와 내부에 커먼코드 파일을 생성한다.

2. 물리적 로직은 커먼코드파일을 기반으로 엔티티 및 환경변수를 셋팅한다. 세팅이 끝나면 서버를 실행한다.

3. 커먼코드를 기반으로 엔티티를 생성하는 모듈은 생성자에 DB에 다녀오는 로직을 작성한다.

4. 생성자에서는 비동기함수를 실행할 수 없다. 따라서 DB에 다녀오라는 함수를 콜하고 생성자는 종료된다.

5. 해당 모듈이 의존성으로 주입되려는 순간, 아직 DB 작업이 완료되지 않아 커먼코드 기반 엔티티를 생성할 수 없어 에러가 발생한다.

 

@Injectable()
export class SetService{
	constructor(
    	@Inject(forwardRef(() => AppService))
    	private readonly appService: AppService, // 에러 발생
    ){
    	this.initDB().then(() => {
        	console.log("DONE INIT SET");
        });
    }
    
    private async initDB(){
    	// ... DB 연결 및 쿼리 로직
    }
}
@Injectable()
export class AppService{
	constructor(
    	@Inject(forwardRef(() => SetService))
    	private readonly setService: SetService, // 에러 발생
    ){
    	this.initDB().then(() => {
        	console.log("DONE INIT APP");
        });
    }
    
    private async initDB(){
    	// ... DB 연결 및 쿼리 로직
    }
}

서버 부팅시 로그를 살펴보면, "DONE INIT ..."이 가장 마지막쯤에 찍힌다. 

각 모듈 객체의 생성자 함수를 실행하고 의존성 주입이 이루어지는데, 생성자에서는 비동기 함수를 사용할 수 없어 각 객체가 생성자함수를 실행했을 뿐 작업을 완료하지는 못했기 때문이다. 

 

해결방법

@Injectable()
export class SetService{

	private static appService: AppService;

	constructor(){
    	this.initDB().then(() => {
        	console.log("DONE INIT SET");
        });
    }
    
    private async initDB(){
    	// ... DB 연결 및 쿼리 로직
    }
    
    public static setAppService(instance: AppService){
    	this.appService = instance;
    }
}
// app.module.ts

...
export class AppModule implements OnModuleInit {
  constructor(private appService: AppService) {}
  onModuleInit() {
    SetService.setAppService(this.appService);
  }
}

앱모듈에 의존성을 강제로 주입한 뒤, 해당 객체를 내부 변수로 세터를 활용하여 사용한다.

테스트를 위해 스태틱 메소드를 생성했고, 앱모듈이 시작될 때 직접 초기화를 해준다.

'Server > NodeJS & NestJS' 카테고리의 다른 글

NestJS) try-catch Error handling with TS  (0) 2025.07.04
싱글스레드에서 비동기 함수의 이해  (0) 2025.06.12
Window nvm-node 설치  (0) 2024.11.22
NodeJS) error log 남기기 - fs  (0) 2023.06.30
NodeJS)nodemon 사용하기  (0) 2023.06.30