
상주형 Slack/Teams 봇의 스케일 아웃 시 발생하는 '이중 응답' 방지 분산 제어 설계
요약
상주형 AI 에이전트가 수평 확장(scale out)될 때 발생하는 '같은 이벤트에 대한 이중 응답' 문제를 다룹니다. 여러 인스턴스가 같은 이벤트 구독을 받을 경우, 중복 처리를 막기 위해 분산 제어 설계가 필수적입니다.
핵심 포인트
- 분산 환경에서 같은 이벤트가 여러 프로세스로 전송될 수 있습니다.
- 이벤트 ID를 활용하여 처리 여부를 가장 먼저 확인해야 합니다.
- 락(Lock) 획득 시 SETNX와 같은 원자적 연산을 사용해야 합니다.
채팅에 상주하며 작동하는 AI 에이전트는 부하나 테넌트 수가 증가함에 따라 단일 프로세스만으로는 처리하기 어려워 여러 인스턴스로 수평 확장(horizontal scale)하게 됩니다. 여기서 많은 사람이 빠지는 함정이 바로 '같은 이벤트에 두 개의 인스턴스가 동시에 반응하여, 같은 답변을 두 번 보내는' 문제입니다. 본 기사에서는 상주 에이전트를 다중 구성으로 만들 때 분산 제어(distributed control)를 어떻게 설계했는지 정리합니다.
단일 인스턴스로 작동하는 봇이라면 이벤트 수신은 항상 하나의 프로세스에서 일어나므로 이중 응답은 발생하지 않습니다. 문제가 명확해지는 것은 가용성이나 처리량(throughput)을 위해 같은 Slack/Teams 앱의 이벤트 구독을 여러 프로세스에서 받는 구성을 했을 때입니다. Socket Mode이든, Events API의 Webhook을 여러 인스턴스 뒤에 로드 밸런싱하는 구성이든, 같은 이벤트가 여러 프로세스로 전송되거나(또는 재전송될) 가능성은 배제할 수 없습니다.
더 까다로운 점은 이 문제가 부하가 낮을 때는 재현되지 않는다는 것입니다. 테넌트 수가 적은 개발 중에는 알아차리지 못하다가, 실제 운영 환경에서 동시 연결 수가 늘어난 시점에 비로소 '같은 질문에 두 개의 답변이 돌아온다'는 클레임으로 표면화됩니다.
Slack의 Events API도, Teams의 Bot Framework도 각 이벤트에는 고유 ID가 부여되어 있습니다. 이를 사용하여 '이미 처리되었는지 여부'를 처음에 확인합니다.
async function handleEvent(event: ChatEvent) {
const key = `event:${event.eventId}`;
// SETNX에 해당. 이미 처리 중/처리되었다면 여기서 차단
...
}
포인트는 세 가지가 있습니다.
- 판별은 반드시 첫 번째 줄에서 수행해야 합니다. 비즈니스 로직 중간에서 판별하면, 그 앞까지의 부작용(LLM 호출 등)이 두 번 실행될 수 있습니다.
- 락(Lock)을 획득할 때는
SETNX와 같은 **원자적 연산(atomic operation)**을 사용해야 합니다. (
본인은 Slack / Teams / Chatwork에 상주하는 법인용 AI 스태프 'HACH'를 개발하고 있습니다. 테넌트 수 증가에 따른 스케일 아웃 시에는 바로 이 설계로 이중 응답을 방지하고 있습니다. 동일한 에이전트를 운영하시는 분들의 참고가 되었으면 좋겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기