💻 프로그래밍/node

[NestJS] 모든게 싱글톤 인스턴스 아니었어? (imports, providers 주의사항)

피트웨어 제이 (FitwareJay) 2022. 7. 21. 22:22

안녕하세요! 개발자 Jay 입니다:D

이번 포스팅에서는 nestjs싱글톤(singleton)에 대해서 주의사항을 말씀드리려고 합니다!

 

아시는 분들은 아시겠지만 nestjs에서는 개발자가 인스턴스를 직접 생성하는 것이 아니라 모듈을 주입하는 과정을 통해 nestjs가 알아서 싱글톤 인스턴스를 생성합니다.

 

제가 최근에 nestjs에 대해 공부를 시작해서 잘 모르고 공부하던 때 생겼던 경험을 공유합니다.

 

 

1. 소켓 응답이 왜 두 번??


소켓으로 클라이언트 메세지 응답이 두번옴...

웹소켓을 스터디하던 중 이상한 현상을 발견했습니다. 클라이언트에서 메시지를 보내면 서버에서 두 번 응답이 왔습니다. 처음에는 서버에서 이벤트를 동일하게 뭔가 잡고 있어서 생기는 오류인가 했는데 그런 건 아니었습니다.

 

좌: nestjs WebSocketGateway 우: 클라이언트 WebSocket

로직을 봐도 특별히 이상한 부분은 없었습니다. 며칠 삽질을 하고 스택오버플로우와 구글링을 뒤지다가 이런 글을 발견했습니다.

 

Inject nestjs service from another module

I've got a PlayersModule and an ItemsModule. I want to use the ItemsService in the PlayersService. When I add it by injection: import { Injectable } from '@nestjs/common'; import { InjectModel }...

stackoverflow.com

여러가지 모듈에 동일한 provider를 추가하지 마라!!

어 음?! 이걸 보고 제가 어떻게 모듈을 주입했는지 확인해봤습니다.

 

모듈 주입 상태

어... 음 메인 app모듈에서 ChatModule을 import 하고 있었고 providers에는 ChatMoudule에서 이미 주입했던 ChatGateway를 주입해주고 있었습니다.  (홀리몰리)

 

바로 imports를 주석 처리하고 소켓통신을 재실행 봤습니다!

 

엇! 하나만 응답이 온다

정상적으로 하나의 응답만 왔습니다. 어... 뭐지? 설마 인스턴스가 두 개 생겼나? nestjs는 싱글톤이라는데? ChatGateway가 imports, providers 두 군데로 주입되어도 싱글톤으로 생성되어야 하는 게 아닌가?라고 생각을 했습니다.

 

그럼 정말 인스턴스가 두 개가 생성되는지 테스트해보겠습니다.

 

2. 디버그 및 이유


constructor에 로그를 넣었다

정말 인스턴스가 두 개가 생긴다면 log가 두 번 찍 혀야 합니다! 두근두근하며 nestjs를 실행했습니다!

 

오! 두번 찍힘

오... 역시 log가 두 번 찍혔습니다. 이로써 인스턴스가 진짜 두 개가 생긴걸 확인 할 수 있었습니다. 그럼 여기서 추측할 수 있는게 imports, providers로 ChatGatwaty가 두 번 주입되었기 때문에 인스턴스가 두개가 생겼다. 결과적으로 WebSocketGateway 인스턴스가 동일한 게 두 개라서 소켓 응답도 두 번이 온 거였다!

 

오케이! 여기까지는 이해가 되었습니다.

그럼 왜! 왜! nestjs에서는 싱글톤으로 생성된다며, 왜 같은걸 두 번 주입했다고 두 개의 인스턴스가 생기는 거야?

 

라고 의문이 듭니다. 그 이유는 바로...

nestjs에서 singleton 인스턴스를 생성하는 범위는 module, providers 범위로 생성하기 때문입니다!
(무조건 singleton으로 생성되는 건 아님)

 

간과하고 있던 게 단순히 이름이 같은 클래스를 여러 군데서 주입해줬다고 다 똑같이 singleton으로 생성되는 게 아닙니다. singleton으로 생성되는 범위(scope)가 있는데 그게 module, providers입니다.

https://docs.nestjs.com/fundamentals/injection-scopes

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

3. 결론, 그럼 어떻게 주입하는 게 best인가?


출처:https://docs.nestjs.com/modules

모듈 단위로 imports 시키는 게 제일 안전하고 깔끔한 방법인 것 같고 뭔가 글로벌하게(?) 주입해주고 싶은 경우 providers를 사용하면 될 것 같습니다. 다만, 제가 아직 nestjs에 능숙하지 않아서 모듈로 주입해주는 경우가 아니라 providers로 주입을 꼭 해줘야 하는 경우를 모르겠습니다...;; 계속 스터디와 실무를 하면서 이런 경우가 있을지 한번 고민해보겠습니다!

 

이 문제는 제가 nestjs의 구조와 싱글톤 인스턴스가 생기는 스코프를 알고 있었으면 경험하지 않았을 문제였네요 ㅎㅎ 이것 때문에 한 2-3일은 삽질한 것 같은데... 그래도 많이 배웠습니다 ㅋㅋㅋ

 

그럼 즐거운 코딩 하시길 바라며, 아디오스~

 

 

참고자료

찍어먹는 nest 기본개념

 

찍어먹는 NestJS - 기본개념

NestJS의 기본 개념을 알아보자

velog.io

https://jun-choi-4928.medium.com/nest-js-behind-the-curtain-712b39abd49c

 

Nest.js behind the curtain

Nest.js 는 정말 견고한 소프트웨어다. SPA 프레임워크인 Angular와 대규모의 안정적인 서비스 운용에 사용되는 Java Spring의 철학을 공유하고 있다고 알고있다. 문서화도 정말 잘되어있어서 원하는 인

jun-choi-4928.medium.com