2025년 3월 5일

김동환·2025년 3월 6일

Today I Learned (TIL) - Bull Queue 적용하여 이메일 인증 비동기 처리

1. Bull Queue란

  • Bull Queue는 Redis 기반의 메시지 큐 시스템으로, 백그라운드에서 작업을 처리할 수 있도록 도와준다.
  • NestJS에서는 @nestjs/bull을 사용하여 쉽게 통합할 수 있다.
  • 이메일 전송과 같이 시간이 오래 걸리는 작업을 비동기적으로 처리하여 서버의 응답 속도를 향상시킬 수 있다.

2. Bull Queue를 사용해야 하는 이유

  • 이메일을 동기적으로 처리하면, SMTP 서버 응답을 기다리느라 응답 속도가 느려질 수 있다.
  • 여러 사용자가 동시에 이메일 인증 요청을 하면, 서버 부하가 증가할 수 있다.
  • Bull Queue를 사용하면 이메일을 큐에 추가한 후 바로 응답을 반환하고, 백그라운드에서 작업을 처리할 수 있다.

3. Bull Queue 적용 과정

1) Bull Queue 관련 패키지 설치

npm install @nestjs/bull bull
  • @nestjs/bull: NestJS에서 Bull Queue를 쉽게 사용할 수 있도록 해주는 모듈
  • bull: Bull Queue의 핵심 라이브러리

2) Redis 설치 및 실행

  • 로컬에서 실행할 경우
    redis-server
  • Docker를 사용할 경우
    docker run --name redis -p 6379:6379 -d redis

3) Bull Queue 등록 (AuthModuleUsersModule 수정)

  • auth.module.ts 수정
import { BullModule } from '@nestjs/bull';

@Module({
  imports: [
    BullModule.registerQueue({
      name: 'email-queue',
      redis: {
        host: 'localhost',
        port: 6379,
      },
    }),
  ],
})
  • users.module.ts 수정
import { BullModule } from '@nestjs/bull';

@Module({
  imports: [
    BullModule.registerQueue({
      name: 'email-queue',
    }),
  ],
  exports: [BullModule],
})
  • UsersModule에서 BullModule을 등록하고 exports 설정을 추가하여 다른 모듈에서도 사용할 수 있도록 한다.

4) AuthService에서 이메일 전송을 Bull Queue로 변경

  • sendVerificationEmail에서 직접 이메일을 전송하는 것이 아니라, Bull Queue에 추가하는 방식으로 변경
import { InjectQueue } from '@nestjs/bull';
import { Queue } from 'bull';

@Injectable()
export class AuthService {
  constructor(@InjectQueue('email-queue') private emailQueue: Queue) {}

  async sendVerificationEmail(email: string, verifyCode: string) {
    await this.emailQueue.add('sendEmail', {
      email,
      verifyCode,
    });
  }
}

5) 이메일을 처리하는 Processor 추가 (email.processor.ts)

import { Process, Processor } from '@nestjs/bull';
import { Job } from 'bull';
import nodemailer from 'nodemailer';

@Processor('email-queue')
export class EmailProcessor {
  @Process('sendEmail')
  async handleSendEmail(job: Job) {
    const { email, verifyCode } = job.data;

    const transporter = nodemailer.createTransport({
      service: 'gmail',
      auth: {
        user: process.env.EMAIL_USER,
        pass: process.env.EMAIL_PASS,
      },
    });

    const mailOptions = {
      from: process.env.EMAIL_USER,
      to: email,
      subject: '이메일 인증 코드',
      text: `인증 코드: ${verifyCode}`,
    };

    try {
      await transporter.sendMail(mailOptions);
    } catch (error) {
      console.error('이메일 발송 실패:', error);
    }
  }
}
  • sendEmail이라는 작업이 큐에 추가되면, email.processor.ts에서 이를 감지하고 실제로 이메일을 전송한다.

4. 테스트 과정

  1. npm run start로 서버를 실행한다.
  2. 회원가입 API 호출 후, 로그에서 이메일 전송 요청이 Bull Queue에 추가되는지 확인한다.
  3. 이메일이 정상적으로 전송되는지 확인한다.

5. 적용 후 개선된 점

  • 이메일 전송 속도가 빨라지고, 서버 부하가 감소했다.
  • 회원가입 시, 이메일 전송이 완료될 때까지 기다릴 필요 없이 바로 응답을 받을 수 있다.
  • 이메일 전송 실패 시 재시도를 설정할 수 있어 안정성이 높아졌다.

6. 다음으로 개선할 점

  • Bull Board를 추가하여 대시보드에서 큐 상태를 확인할 수 있도록 개선할 수 있다.
  • 이메일 전송 실패 시 재시도 로직을 추가하여 안정성을 더욱 높일 수 있다.
  • 이메일 템플릿을 추가하여 보다 직관적인 인증 메일을 보낼 수 있도록 개선할 수 있다.

이번 작업을 통해 Bull Queue를 활용한 비동기 이메일 전송 시스템을 적용하였고, 이를 통해 서버의 응답 속도를 개선하고 부하를 줄일 수 있었다.

profile
Node.js 7기

0개의 댓글