자동화 slecs

Discord 봇 버튼 응답 지연을 큐 기반 워커로 해결

목차

Discord 봇의 버튼 클릭 이벤트를 안정적으로 처리하기 위해 큐 기반의 워커 시스템을 만들었다. 처음에는 버튼 클릭이 들어오면 바로 처리했는데, 동시 요청이 많아지거나 각 작업에 시간이 걸리면서 문제가 생기기 시작했다. 그래서 액션을 큐에 넣고 별도 워커가 처리하는 구조로 변경했다.

왜 큐 처리가 필요했나

Discord에서 사용자가 버튼을 클릭하면 봇이 3초 안에 응답해야 한다. 시간을 벌기 위해 보통 "작업 처리 중…" 메시지를 먼저 보낸 다음 백그라운드에서 실제 작업을 진행한다. 근데 백그라운드 작업이 여러 개 쌓이면 어떻게 될까?

  • 동시성 문제: 같은 데이터에 대한 버튼 클릭이 동시에 들어올 수 있음
  • 레이트 리미팅: 외부 API 호출이 포함되면 배치로 처리해야 할 수도 있음
  • 재시도 로직: 네트워크 실패 시 단순히 실패 처리가 아니라 재시도가 필요한 경우가 많음
  • 우선순위: 긴급한 액션과 일반 액션을 구분해서 처리하고 싶을 수 있음

이런 이유로 큐 패턴이 필요했다.

워커 패턴의 기본 구조

큐 기반 처리의 기본 형태는 다음과 같다:

# Discord 이벤트 핸들러: 액션을 큐에 추가만 함
@bot.event
async def on_button_click(interaction):
    action = {
        "type": "button_action",
        "user_id": interaction.user.id,
        "action_id": interaction.custom_id,
        "timestamp": datetime.now()
    }
    await action_queue.put(action)
    await interaction.response.defer()

# 워커: 큐에서 꺼내서 실제 처리
async def process_actions():
    while True:
        action = await action_queue.get()
        try:
            await handle_action(action)
        except Exception as e:
            logger.error(f"Failed to process action: {e}")
            # 재시도 로직이나 dead-letter 큐 처리
        finally:
            action_queue.task_done()

이렇게 분리하면 이벤트 핸들러는 빨리 끝나고, 워커가 천천히 처리해도 괜찮다.

큐 기반 처리의 실제 이점

항목 직접 처리 큐 기반 처리
응답 속도 작업 시간에 따라 가변 항상 빠름 (큐 추가만 함)
동시 요청 처리 스레드/코루틴 추가 필요 워커 수로 조절 가능
실패 처리 매번 개별 처리 재시도 정책 통일
모니터링 여러 곳에서 발생 한 곳(워커)에서 추적
스케일링 코드 변경 필요 워커 인스턴스만 추가

큐를 사용하면 일관된 방식으로 모든 액션을 처리할 수 있다는 게 큰 장점이다. 중앙집중식 에러 핸들링, 로깅, 재시도 정책을 한 번만 구현하면 모든 액션에 적용되니까.

운영 관점에서 챙길 점

이렇게 워커를 만들 때 생각해야 할 것들:

  • 워커 상태 모니터링: 워커가 죽어도 알 수 있도록 헬스체크 추가
  • 큐 크기 관찰: 큐가 계속 커지면 워커를 더 띄워야 한다는 신호
  • 유독성 메시지 처리: 어떤 액션이 계속 실패하면 무한 재시도하지 않도록 주의 (dead-letter 큐나 최대 재시도 횟수 설정)
  • 작업 타임아웃: 특정 워커가 무한 대기하지 않도록 타임아웃 설정

особ히 Discord처럼 외부 서비스와 연동할 때는 레이트 리미팅을 고려해야 한다. API 호출이 많으면 순차 처리로 변경하거나, 여러 워커를 띄웠을 때 동시 호출 수를 제한하는 세마포어를 써야 할 수도 있다.

왜 이 작업이 필요했는가

팀에서 Discord 봇의 응답 속도가 불안정하다는 피드백을 받았다. 버튼을 클릭해도 가끔 응답이 느려서 사용자가 불편함을 겪고 있었다. 문제는 몇 명이 동시에 버튼을 누르거나 한 명의 요청이 느린 API 호출을 포함할 때 발생했다.

큐 기반 워커를 만들면 이벤트 핸들러는 항상 3초 안에 응답할 수 있게 되고, 실제 작업은 따로 처리되니까 응답 지연이 없다. 단순 구조 변경이지만 운영 안정성이 크게 올라간다.

비슷한 상황에서 배운 것

이전에도 비슷한 패턴을 여러 곳에서 본다:
- 이메일 발송: 사용자가 "메일 보내기" 버튼을 누르면 즉시 "발송 예약됨" 메시지를 보여주고, 워커가 실제로 메일을 보냄
- 이미지 업로드: 업로드 완료 응답은 빠르게 주고, 썸네일 생성·저장은 별도 워커가 담당
- 결제 처리: 결제 요청을 큐에 담고, 전용 워커가 순차적으로 처리 (동시성 문제 방지)

패턴은 같지만 도메인에 따라 우선순위나 재시도 정책은 달라진다. 어쨌든 핵심은 "사용자에게 빠른 응답 + 백그라운드 안정적 처리"다.

이번 작업으로 자동화 파이프라인이 한 단계 견고해졌다. 앞으로 비슷한 구조가 필요한 곳이 있으면 이 패턴을 참고하면 될 것 같다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.