Nest 공식문서 아무거나

송은우·2022년 3월 27일
0

scope

생각보다 훨씬 독특한 경우를 따름.
기본적으로 singleton이기에, 모든 것들이 한 번 생성되고 끝남. 이게 생각보다 커다란 영향을 끼침.
예를 들면 app.service에서 Date.now()를 호출하는 경우. 이 결과는 무조건 처음 application lifecycle의 시작점과 동일한 결과만을 반환함.
이때 쓰는 것이

@Injectable({scope:Scope.REQUEST}) 
@Injectable({scope:Scope.TRANSIENT}) 

request는 request마다 새로운 객체를 만들고, 그게 끝나면 사라진다는 느낌.
Transient는 consumer마다 공유되지 않고, 새로운 객체를 만들고, 1 consumer 1객체를 따름.controller, service마다 다 생성됨

controller도 당연하지만, scope를 가질 수 있다.
모듈은 안 된다
컨트롤러가 request 스코프를 가져간다면, 하위 provider같은 것들도 전부 request를 따라간다.

scope가 바뀌면 @Req느낌 보다는

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) {}
}

REQUEST를 넣음으로써 original request object에 access가 가능하다.

순환 종속성

class A => class B 필요
class B => class A 필요 무한 참조가 발생함
웬만하면 피하는 것이 좋지만. 항상 그럴 수 없기에, Nest는 처리하는 방법이 2가지가 있다.
forward referencing, ModuleRef라는 2가지 방법이 있음.

주의)
당연하지만, 자기 자신을 포함한 파일을 include하면 안된다.

Forward Referencing

아직 완벽하게 정의되지 않은 class를 가져오는 것이 가능하다.
forwardRef()라는 함수를 이용함.
CatsService와 CommonService가 서로에게 의존한다면, 양쪽이 @Inject()와 forwardRef()를 사용할 수 잇음. 그렇지 않으면 nest는 instant화를 하지 않음. 충분한 메타데이터를 얻지 못하기 때문

@Injectable()
export class CatsService {
  constructor(
    @Inject(forwardRef(() => CommonService))
    private commonService: CommonService,
  ) {}
}
@Injectable()
export class CommonService {
  constructor(
    @Inject(forwardRef(() => CatsService))
    private catsService: CatsService,
  ) {}
}

이렇게 두 파일에 dependency를 관리해줘야 함.
단 인스턴스화 순서가 불확실하기에, 순서에 따라 방식이 바뀌는지 확인해야 한다.
scope.REQUEST와 같이 사용된다면, undeifned dependency를 불러올 수 있기에 주의해야 한다.
ModuleRef클래스로 처리하는 방법이 있다. 한쪽에서 먼저 처리하는 느낌... Module Reference를 참조하는 것

Lazy-Loading Modules

서버리스에 가장 필요한 것. 모든 모듈이 실행과 동시에 실행 될 경우, 모든 것을 시작과 동시에 로딩을 시킬 경우, 콜드스타트를 기준으로 설계된 serverless에 병목현상을 일으킬 수 있다.

const { LazyModule } = await import('./lazy.module');
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule);

이렇게 처리할 수 있는데, 여기서 module ref가 나온다.
lazy module은 첫 로드만 늦게 하고, 그 다음에는 캐시되어 빠르게 처리할 수 있다.

Load "LazyModule" attempt: 1
time: 2.379ms
Load "LazyModule" attempt: 2
time: 0.294ms
Load "LazyModule" attempt: 3
time: 0.303ms

compilerOptions.module을 esnext로 설정하고 값으로 node를 사용해 compilerOptions.moduleResolution 속성을 추가한다.
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node",
...
}

tsconfig.json을 바꿔야 한다.처리를 해야 webpack의 경우 사용할 수 있다.
worker/cron job/lambda &serverless/web hook 같이 입력 값에 따라 다른 서비스를 켜야 하는 상황에서 사용된다.
일반 모놀리식 어플리케이션은 필요 없을 듯?
단순하게 백그라운드, 특정 시간에 타이머, 서버리스 라고 생각하면 될듯?

@Injectable()
export class CatsService {
  constructor(private lazyModuleLoader: LazyModuleLoader) {}
}

이런 사용 예시
아니라면
module loader를 app.get으로 NestInstance에서 가져올 수 있음
lazyModuleLoader를 단순하게 @nestjs/core에서 가져올 수도 있고, 밑의 방법으로 할 수도 있다.
const lazyModuleLoader = app.get(LazyModuleLoader);
도 가능

const { LazyModule } = await import('./lazy.module');
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule);

graphql 의 경우 lazyloader가 불가능함

profile
학생의 마음가짐으로 최선을 다하자

0개의 댓글