Injection Scope

이연중·2021년 10월 18일
1

NestJS

목록 보기
15/22
post-thumbnail

Node.js는 단일 쓰레드 환경에서 구동되며, 그렇기에 Nestjs는 싱글톤 인스턴스의 사용을 지향한다.

하지만, GraphQL 어플리케이션의 요청별 캐싱, 요청 추적 및 멀티 테넌시와 같이 request 기반 라이프사이클을 원하는 경우가 있다.

Injection Scopes는 이러한 경우를 위해 인스턴스의 라이프사이클을 설정할 수 있게 한다.

Scope의 3가지 모드


  • 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 hierarchy


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로 유지)

Request Provider


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 값을 구성한다.

Performance


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

profile
Always's Archives

1개의 댓글

comment-user-thumbnail
2022년 4월 14일

좋은 글 잘 읽었습니다.

답글 달기