순환 의존도 아닌데 can't resolve dependencies가 난 이유
문제 발생
UserService를 다른 모듈의 컨트롤러에 주입했더니 부팅이 실패했습니다. 순환 의존은 없었습니다.
Nest can't resolve dependencies of the OrderController (?).
Please make sure that the argument UserService at index [0]
is available in the OrderModule context.OrderModule의 providers에 UserService를 추가하니 뜨긴 했는데, 그때부터 캐시가 비어 있는 것처럼 동작했습니다.
원인 분석
두 가지가 겹쳐 있습니다.
첫째, provider는 모듈에 갇혀 있습니다. 공식 문서가 명시합니다 — 모듈은 기본적으로 provider를 캡슐화하므로, 현재 모듈에 속하거나 가져온(imported) 모듈이 명시적으로 내보낸(exported) provider만 주입할 수 있습니다.
즉 공유하려면 두 가지가 모두 필요합니다 — 소유한 모듈이 exports에 넣고, 쓰려는 모듈이 그 모듈을 imports에 넣는 것입니다. 둘 중 하나만으로는 안 됩니다.
둘째, providers에 다시 넣으면 별개 인스턴스가 생깁니다. 오류는 사라지지만 그 모듈만의 새 인스턴스를 갖게 됩니다. 문서가 강조하는 것이 이 지점입니다 — Nest에서 모듈은 기본적으로 싱글턴이므로 여러 모듈이 같은 provider 인스턴스를 손쉽게 공유할 수 있습니다. 그 이점을 스스로 버린 셈입니다. 캐시가 비어 보였던 이유가 이것입니다.
해결 방안
- 소유 모듈에서 내보냅니다.
@Module({
providers: [UserService],
exports: [UserService], // 이게 없으면 밖에서 주입할 수 없다
})
export class UserModule {}- 쓰는 모듈에서 가져옵니다.
@Module({
imports: [UserModule], // providers에 UserService를 넣지 않는다
controllers: [OrderController],
})
export class OrderModule {}- 네 속성의 역할을 구분합니다.
| 속성 | 의미 |
|---|---|
providers | 이 모듈이 소유해 인스턴스를 만드는 provider |
controllers | 이 모듈의 컨트롤러 |
imports | 필요한 provider를 내보내는 다른 모듈 목록 |
exports | providers 중 다른 모듈에 공개할 것 |
-
providers에 남의 서비스를 넣지 않습니다. 오류를 없애는 가장 빠른 방법이지만, 인스턴스가 갈라지면서 상태·캐시·커넥션이 두 벌이 됩니다. 오류 메시지가 사라진다고 해결된 것이 아닙니다. -
모듈도 다시 내보낼 수 있습니다. 여러 곳에서 같은 조합을 쓸 때 유용합니다.
@Module({
imports: [UserModule, AuthModule],
exports: [UserModule, AuthModule], // 이 모듈을 가져오면 둘 다 따라온다
})
export class CoreModule {}-
전역 모듈은 아껴 씁니다.
@Global()을 붙이면imports없이 쓸 수 있지만, 의존 관계가 코드에 드러나지 않습니다. 설정(ConfigModule)처럼 정말 어디서나 필요한 것에만 씁니다. -
오류 메시지를 그대로 읽습니다.
available in the XxxModule context가 핵심입니다 — "이 모듈의 문맥에서 보이지 않는다"는 말이고, 답은 거의 항상exports와imports둘 중 하나입니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.