2024-11-27 CH-6 최종 프로젝트 8 bull Queue 공부

MOON·2024년 12월 4일
0

내일배움캠프 과제

목록 보기
42/48

오늘은 한번은 사용해 볼 것 같은 Bull queue 팀원들 각자 같이 공부해 해보았습니다.

1. Bull Queue란 무엇인가?

Bull QueueNode.js를 위한 강력한 작업 큐 라이브러리입니다. 이를 통해 작업(job)을 처리하고, 순서를 유지하며, 비동기 작업을 효율적으로 관리할 수 있습니다. 주로 다음과 같은 상황에서 사용됩니다:

백그라운드 작업 처리: CPU 집약적 작업을 메인 스레드에서 분리.
스케줄링 작업: 특정 시간에 실행하거나 주기적으로 실행해야 할 작업 관리.
다중 사용자 요청 관리: 동시에 많은 사용자가 자원을 요청할 때 충돌 없이 순서대로 처리.

주요 특징

  • Redis를 기반으로 작동.
  • 작업 우선순위 설정 가능.
  • 재시도 및 실패 관리.
  • 작업 이벤트 추적 및 작업 상태 확인 가능.

2. Bull Queue 설치 및 Redis 연결 설정

설치
우선, Bull Queue와 Redis 클라이언트를 설치합니다:

npm install bull ioredis

Redis 클라이언트 설정
Redis 클라이언트를 설정하여 Bull Queue가 Redis와 통신할 수 있도록 구성합니다.

import Redis from "ioredis";

const redis = new Redis({
  host: "redis-13695.c340.ap-northeast-2-1.ec2.redns.redis-cloud.com",
  port: 13695,
  password: "u53JYjT3ukkdBM2StSS1C7jvfqaqfQhs",
  retryStrategy: (times) => Math.min(times * 100, 2000),
});

3. Bull Queue를 이용한 아이템 처리 구현

작업 큐 생성
Queue 클래스를 사용하여 큐를 생성합니다. Redis 설정을 함께 전달합니다.

import Queue from "bull";

const itemQueue = new Queue("item-test", {
  redis: {
    host: "redis-13695.c340.ap-northeast-2-1.ec2.redns.redis-cloud.com",
    port: 13695,
    password: "u53JYjT3ukkdBM2StSS1C7jvfqaqfQhs",
  },
});

작업 처리 로직
process 메서드를 통해 큐에 들어온 작업을 처리합니다. 예제에서는 아이템 재고를 관리하며, 재고가 있으면 소비하고 없으면 실패를 반환합니다.

let itemStock = 5; // 아이템 재고 수

itemQueue.process(async (job) => {
  if (itemStock > 0) {
    itemStock -= 1;
    console.log(
      `✅ ${job.data.userId}가 아이템을 소비했습니다. 남은 재고: ${itemStock}`
    );
    return { success: true, remainingStock: itemStock };
  } else {
    console.log(`❌ ${job.data.userId}가 요청했지만, 재고가 없습니다.`);
    return { success: false, remainingStock: 0 };
  }
});

4. 테스트: 사용자 요청 시뮬레이션

테스트 작업 추가
여러 사용자가 동시에 아이템을 요청하는 상황을 시뮬레이션합니다. add 메서드를 통해 작업을 큐에 추가할 수 있습니다.

async function testQueue() {
  const users = [
    "User1",
    "User2",
    "User3",
    "User4",
    "User5",
    "User6",
    "User7",
    "User8",
  ];

  users.forEach(async (userId) => {
    console.log(`📤 ${userId}가 아이템을 요청합니다.`);
    await itemQueue.add({ userId }); // 작업 추가
  });
}

testQueue();

5. 작업 완료 및 실패 이벤트 처리

Bull Queue는 작업의 완료 및 실패 이벤트를 감지하여 처리할 수 있습니다.

itemQueue.on("completed", (job, result) => {
  console.log(`🎉 작업 완료: ${job.id} - 결과:`, result);
});

itemQueue.on("failed", (job, err) => {
  console.log(`⚠️ 작업 실패: ${job.id} - 에러:`, err.message);
});

6. 큐 초기화: Redis 키 삭제

작업 테스트 후, Bull Queue와 관련된 모든 Redis 키를 삭제하려면 다음 함수를 실행하면 됩니다.

async function clearBullQueue(queueName) {
  const pattern = `bull:${queueName}:*`; // Bull Queue 키 패턴
  const keys = await redis.keys(pattern); // 해당 패턴의 모든 키 가져오기

  if (keys.length > 0) {
    await redis.del(keys); // 모든 키 삭제
    console.log(`${keys.length}개의 키를 삭제했습니다:`, keys);
  } else {
    console.log("삭제할 키가 없습니다.");
  }
}

clearBullQueue("item-test");

7. 결과

테스트 실행 결과, 재고가 다 떨어질 때까지 작업이 순차적으로 처리됩니다. 재고가 없는 경우 작업은 실패 처리됩니다. 이를 통해 동시에 많은 요청을 안정적으로 처리할 수 있는 것을 확인할 수 있었습니다.

8. (추가 설명) 작업 병렬 처리 설정

itemQueue.process 메서드는 기본적으로 작업을 하나씩 처리하지만, 첫 번째 인자로 숫자를 전달하여 병렬로 처리할 worker의 수를 지정할 수 있습니다.

itemQueue.process(2, async (job) => {
  if (itemStock > 0) {
    itemStock -= 1;
    console.log(
      `✅ ${job.data.userId}가 아이템을 소비했습니다. 남은 재고: ${itemStock}`
    );
    return { success: true, remainingStock: itemStock };
  } else {
    console.log(`❌ ${job.data.userId}가 요청했지만, 재고가 없습니다.`);
    return { success: false, remainingStock: 0 };
  }
});

결과
이 설정을 통해 최대 2개의 작업이 동시에 처리됩니다.
병렬 처리는 작업 큐를 더욱 효율적으로 사용하며, 특히 요청이 많거나 작업 시간이 긴 경우 유용합니다.

오늘의 회고
팀원들이랑 이야기를 할떄 node.js싱글 스레드 기반이기에 이것이 필요한지에 대해 의문을 가졌습니다. 얼추 로직으로 순서제어가 가능해 보이는데 Bull queue를 써야 되는 건지에 대해 고민하다 튜터님의 피드백으로 이러한 queue시스템을 경험해보는 것이 좋을 것이다라는 피드백을 받아 사용해 보자라는 결론이 나왔습니다. 그리고 Bull queue를 사용하는 편이 편할 것 같아 보이네요. 굿!

오늘도 화이팅

profile
안녕하세요

0개의 댓글

관련 채용 정보