Node.js는 단일 쓰레드 환경에서 구동되며, 그렇기에 Nestjs는 싱글톤 인스턴스의 사용을 지향한다.
하지만, GraphQL 어플리케이션의 요청별 캐싱, 요청 추적 및 멀티 테넌시와 같이 request 기반 라이프사이클을 원하는 경우가 있다.
Injection Scopes는 이러한 경우를 위해 인스턴스의 라이프사이클을 설정할 수 있게 한다.
DEFAULT: 싱글턴 인스턴스가 사용되며, 해당 인스턴스가 전체 응용 프로그램에서 공유된다. 인스턴스의 수명은 어플리케이션의 생명주기와 직접적으로 연결
REQUEST: 들어오는 요청마다 인스턴스가 생성되며, 요청에 대한 응답처리가 완료되면, 인스턴스가 garbage-collected 처리 된다.(동일한 요청에 대해서는 동일한 인스턴스가 공유된다)
TRANSIENT: 모든 작업이나 서비스에 대해 인스턴스가 생성되며, 작업이나 서비스 로직 처리가 완료되면 사라진다.
Service, Module, Controller 별 적용
Service
import { Injectable, Scope } from '@nestjs/common';
@Injectable({
scope: Scope.TRANSIENT
})
Module
providers : [{
provide : PRODUCT,
useValue: Product_Token,
scope : Scope.REQUEST
}]
Controllers
@Controller({ path: 'product', scope: Scope.REQUEST })
scope는 injection chain을 상위 layer에 위임한다.
CatsController <- CatsService <- CatsRepository 이렇게 의존성 관계가 성립된다고 하고, CatsService는 REQUEST Scope를 적용, 나머지는 Singleton인 DEFAULT Scope를 적용했다고 하자
injection chain은 상위 layer에 위임되기에 CatsService의 의존성을 주입받은 CatsController는 그 injection Scope까지 위임받게 되어 DEFAULT Scope -> REQUEST Scope로 변한다.(CatsRepository는 DEFAULT Scope로 유지)
HTTP 서버 기반 어플리케이션(express, fastify)에서 Provider에 REQUEST Scope를 적용할 때, 요청 객체를 참조 할 수 있다.
REQESUT 객체를 삽입해 구현한다.
import { Injectable, Scope, Inject } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {
constructor(@Inject(REQUEST) private request: Request) {}
}
Micro Service나 GraphQL 어플리케이션의 경우에는 REQUEST 대신 CONTEXT를 삽입한다.
import { Injectable, Scope, Inject } from '@nestjs/common';
import { CONTEXT } from '@nestjs/graphql';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {
constructor(@Inject(CONTEXT) private context) {}
}
그 다음, request를 속성으로 포함하도록 context 값을 구성한다.
REQUEST, TRANSIENT Scope를 사용하는 것은 어플리케이션 성능에 영향을 미친다.
Nestjs는 가능한 많은 메타데이터를 캐싱하려고 하지만, 위 두 Scope를 이용하게 되면, 각 요청에 대해 혹은 각 작업 or 서비스 로직마다 인스턴스를 만들어야 한다.
이로인해 평균 응답 시간과 전체 벤치마킹 결과가 느려지게 된다.
따라서, REQUEST, TRANSIENT Scope를 사용해야 하는 경우가 아니라면, DEFAULT Scope를 사용하는 것이 좋다.
https://docs.nestjs.kr/fundamentals/injection-scopes#request-provider
https://dev.to/this-is-learning/a-deep-dive-into-the-nestjs-injection-scope-39ih
좋은 글 잘 읽었습니다.