포시코딩

3월9일 - @nestjs/event-emitter 본문

TIL

3월9일 - @nestjs/event-emitter

포시 2023. 3. 10. 00:27
728x90

개요

Node.js의 Event Emitter는 특정 이벤트에 리스너 함수를 달아서 

이벤트가 발생했을 때 이를 캐치할 수 있도록 만들어진 api라고 한다.

 

오늘은 Nest.js에서 Event Emitter를 쓰는 법을 알아보고자 한다.

 

기본적으로 공식 홈페이지에서의 안내를 따랐다.

https://docs.nestjs.com/techniques/events

 

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

 

설치

npm i @nestjs/event-emitter

 

사용방법

공식 홈페이지에 있는 사용방법을 똑같이 적는건 의미 없으니 

내가 사용한 방식을 기록하는게 좋을 것 같다.

 

import { EventEmitter2 } from '@nestjs/event-emitter';

@Injectable()
export class Service {
  constructor(
    private eventEmitter: EventEmitter2
  ) {}

특이사항으로는 EventEmitter2를 사용한다는 것이다.

그냥과 2의 차이점이 뭔진 모르겠지만 이렇게 사용하라고 안내가 되어 있으니 말을 듣자.

 

service

  private waitFinish(eventName: string, sec: number) {
    return new Promise((resolve, reject) => {
      const wait = setTimeout(() => {
        this.eventEmitter.removeAllListeners(eventName);
        resolve({ 
          message: '다시 시도해주세요.',
        });
      }, sec * 1000);
      const listenFn = ({ success, exception }: { success: boolean, exception?: HttpException }) => {
        clearTimeout(wait)
        this.eventEmitter.removeAllListeners(eventName);
        success ? 
          resolve({ message: '참여 성공' }) : 
          reject(exception);
      };
      this.eventEmitter.addListener(eventName, listenFn);
    });
  }

  async addJoin(meetupId: number, userId: number, eventName: string) {
    try {
      const join = await this.getJoin(meetupId, userId);
      if (!_.isNil(join)) {
        throw new ConflictException(`이미 참여하고 있는 유저입니다.`);
      }
      const meetup = await this.getMeetup(meetupId);
      if (meetup.headcount <= meetup.joins.length) {
        throw new ForbiddenException('정원이 다 찼습니다.');
      }
      await this.joinRepository.insert({
        meetupId, userId
      });
      return this.eventEmitter.emit(eventName, { success: true });
    } catch (err) {
      return this.eventEmitter.emit(eventName, { success: false, exception: err });
    }
  }

waitFinish() 함수를 실행시킨 상태로 wait에 의해 2초간 기다리게 되는데

같이 사용하는 Bull Queue에 의해 addJoin() 함수가 실행되어 eventEmitter.emit이 실행되고

 

waitFinish()의 eventEmitter.addListener()에서 잡아내 세팅해놓은 함수가 실행되는 코드이다.

 

나는 Bull Queue를 통한 대기열을 만들어 해당 대기열에서의 job의 로직이 처리되고 나서 

다시 클라이언트로 응답하기 위해 사용했는데

 

다른 사용처로는 어떤 상태변화가 생겼을 때 그 상태변화에 대응해야 하는 여러 구독자가 있을 경우 사용한다고 한다.

즉, 하나의 상황에 대해 여러 행위를 하기 위해 사용한다는 것

 

아직까지는 쓰고 싶어도 마땅한 쓰임새가 뚜렷하게 떠오르지 않는데

그래도 무기 하나를 얻은 셈이니 언젠가 다시 쓸 날이 오길 기다려야겠다.

728x90