HeyRatty
← 블로그 목록
워크플로우 설계2026년 7월 24일· 약 10분

AI Agent 동시 실행 제어, 같은 업무가 겹칠 때 락과 큐를 쓰는 기준

스케줄·웹훅·재시도가 겹쳐 같은 AI 업무가 동시에 실행될 때, 업무 키와 중첩 정책, 락·리스·대기열, 취소·관찰 지표를 정하는 실무 기준을 정리합니다.

#AI 자동화#AI Agent#업무자동화#운영체계#체크리스트

매일 오전 9시 영업 보고서를 만드는 Agent가 있다고 해보겠습니다. 스케줄러가 실행을 시작한 직후 담당자가 '다시 만들기'를 누르고, 지연된 웹훅까지 도착하면 같은 고객·같은 날짜의 업무가 세 번 동시에 시작될 수 있습니다.

마지막에 결과 파일 하나만 남았다고 안심하기는 어렵습니다. 세 실행이 API 사용량을 함께 소비하고, 서로 다른 시점의 CRM 데이터를 읽고, 저장 순서에 따라 오래된 결과가 새 결과를 덮을 수도 있습니다. 멱등성은 중복 부수효과를 줄이지만 실행 중 경합과 자원 점유까지 자동으로 해결하지는 않습니다.

이미지: Wikimedia Commons 「RailroadSwitch 20200801 014921.jpg」 · Ka23 13 · CC BY-SA 4.0. 일본 지바현 철도 분기기 유지보수 장면을, 하나의 공유 자원에 여러 작업이 겹칠 때 조정하는 비유로 사용했습니다.
이미지: Wikimedia Commons 「RailroadSwitch 20200801 014921.jpg」 · Ka23 13 · CC BY-SA 4.0. 일본 지바현 철도 분기기 유지보수 장면을, 하나의 공유 자원에 여러 작업이 겹칠 때 조정하는 비유로 사용했습니다.

핵심 요약

  • 먼저 어떤 요청을 '같은 업무'로 볼지 업무 키를 정합니다. 실행 ID가 아니라 고객·문서·업무 종류·기준 시각처럼 비즈니스 의미가 있는 값이어야 합니다.
  • 겹친 요청을 허용할지, 건너뛸지, 한 건만 기다릴지, 모두 줄 세울지, 기존 실행을 취소하고 바꿀지 먼저 선택합니다.
  • 짧은 상태 선점은 원자적 쓰기나 락으로 처리하고, 오래 걸리는 AI 작업은 소유자와 만료가 있는 리스, 제한된 대기열, 동시성 한도를 함께 둡니다.
  • 락 해제는 자신이 획득한 소유자 토큰과 일치할 때만 허용합니다. 워커가 죽거나 리스가 만료된 뒤의 복구 흐름도 별도로 정합니다.
락은 자동화를 오래 붙잡는 장치가 아니라, 지금 이 업무를 맡을 실행자를 한 명으로 정하는 규칙입니다.

동시 실행 제어는 멱등성·타임아웃과 무엇이 다를까

동시 실행 제어는 '지금 누가 실행할 수 있는가'를 정합니다. 멱등성은 같은 업무가 다시 요청됐을 때 최종 메일·레코드·결제가 중복되지 않게 만들고, 타임아웃은 언제 더 기다리지 않을지 정합니다.

여러 단계 중 일부만 끝났다면 부분 실패 복구가 이어갈 지점과 보상 작업을 다룹니다. 네 규칙은 대체 관계가 아닙니다. 락으로 한 실행만 남겨도 그 실행이 재시도되거나 중간 단계에서 실패할 수 있습니다.

먼저 '같은 업무'라고 판단할 키를 정합니다

락 제품을 고르기 전에 충돌 범위를 적어야 합니다. 키가 너무 넓으면 무관한 고객 업무까지 줄을 서고, 너무 좁으면 같은 요청이 다른 키로 들어와 동시에 실행됩니다.

  • 조직·고객 범위: tenant_id, workspace_id, customer_id처럼 데이터와 권한 경계가 되는 값
  • 업무 종류: 일일 보고서, 문의 분류, 계약서 요약, 지식 인덱스 갱신처럼 결과의 목적을 나타내는 값
  • 대상 자원: 문서 ID, 주문번호, 캠페인 ID, 데이터 소스 ID처럼 실제로 함께 수정하면 충돌하는 값
  • 업무 시점·버전: 영업일, 정산 주기, 문서 버전처럼 어느 결과가 최신인지 가르는 값

예: org:acme:daily-sales:2026-07-24 / customer:4312:inquiry-classification / document:contract-882:v7:summary

매번 새로 만드는 run_id만 키로 쓰면 모든 실행이 서로 다른 업무로 보입니다. 반대로 'all-ai-jobs' 같은 전역 키는 한 고객의 긴 문서 분석 때문에 다른 고객의 짧은 문의 분류까지 멈추게 합니다.

겹쳤을 때 행동은 다섯 가지 중 하나로 고릅니다

  1. 허용(Allow): 대상 자원이 다르고 외부 시스템 한도도 충분하면 함께 실행합니다. 고객별 문의 분류처럼 키가 다른 작업이 대표적입니다.
  2. 건너뛰기(Skip/Forbid): 이전 결과가 아직 유효한 정기 집계라면 새 실행을 만들지 않습니다. 건너뛴 사실과 이유는 기록합니다.
  3. 한 건만 대기(Buffer one): 실행 중 새 요청이 와도 최신 한 건만 남깁니다. 같은 버튼을 여러 번 누르는 화면이나 최신 보고서 생성에 잘 맞습니다.
  4. 모두 대기(Buffer all): 주문·정산처럼 각 업무를 하나도 버리면 안 될 때 순서대로 처리합니다. 대기열 크기와 최대 대기 시간은 반드시 제한합니다.
  5. 교체(Replace/Cancel): 이전 계산이 더 이상 쓸모없고 안전하게 취소할 수 있을 때 기존 실행을 멈추고 최신 요청으로 바꿉니다.

Kubernetes CronJob은 Allow·Forbid·Replace를, Temporal Schedule은 Skip·BufferOne·BufferAll·CancelOther 같은 중첩 정책을 제공합니다. 제품 이름을 그대로 따라 하기보다 업무 손실, 최신성, 취소 가능성에 맞춰 정책을 정하는 것이 먼저입니다.

락·리스·큐·동시성 한도는 역할이 다릅니다

  • 고유 제약·조건부 쓰기: 공유 DB에 실행 상태를 원자적으로 선점해 같은 업무 키의 최초 실행자 한 명을 정합니다.
  • 트랜잭션·행 락: 짧은 읽기-수정 구간을 보호합니다. 수분 걸리는 모델 호출 전체를 DB 트랜잭션 안에 넣는 용도로 쓰지 않습니다.
  • 분산 리스: 여러 워커가 같은 공유 자원을 잡을 때 소유자 토큰과 만료 시각을 둡니다. 실행 중에는 소유권을 갱신하고, 소유자만 해제합니다.
  • 대기열: 지금 실행할 수 없는 업무를 순서와 우선순위에 따라 보관합니다. 무제한 적재가 아니라 용량·최대 대기·폐기 규칙이 있는 대기열이어야 합니다.
  • 세마포어·동시성 한도: 한 명만 허용하는 대신 독립적인 작업 N개까지 허용합니다. 모델 API, CRM, 파일 변환 워커의 처리 한도 보호에 적합합니다.

실무에서는 상태 선점과 긴 실행을 분리하는 편이 안전합니다. DB에서 RUNNING 상태와 소유자를 짧게 기록한 뒤 트랜잭션을 끝내고, Agent는 리스 갱신과 단계 상태를 남기며 실행합니다.

안전한 락과 리스를 만드는 6단계

  1. 업무 키와 보호할 공유 자원을 문서화합니다. 키 예시, 충돌하는 요청, 동시에 실행해도 되는 요청을 함께 적습니다.
  2. 원자적으로 소유권을 획득합니다. 확인 후 쓰기처럼 두 단계로 나누지 말고 고유 제약, 조건부 갱신, 트랜잭션 중 하나를 사용합니다.
  3. owner_token과 expires_at을 저장합니다. 워커 ID만 재사용하지 말고 획득 시도마다 구분 가능한 토큰을 발급합니다.
  4. 획득 실패 시 정책을 적용합니다. 즉시 오류로 끝낼지, 한 건만 기다릴지, 기존 실행 상태를 보여줄지 응답을 정합니다.
  5. 실행 중에는 소유권이 여전히 자신의 것인지 확인하며 갱신합니다. 갱신 실패 뒤에는 외부 쓰기를 계속하지 않고 상태 확인 또는 사람 인계로 전환합니다.
  6. 해제와 만료 뒤 복구를 분리합니다. 정상 해제는 소유자 일치 조건으로 처리하고, 만료된 실행은 기존 결과를 대조한 뒤 재실행 여부를 결정합니다.

만료 시간은 짧을수록 안전하다는 식으로 정할 수 없습니다. 너무 길면 죽은 워커의 복구가 늦고, 너무 짧으면 정상 실행 중 소유권이 넘어갈 수 있습니다. 실제 실행 시간 분포, 갱신 주기, 네트워크 지연, 복구 목표를 보고 정합니다.

대기열이 쌓여도 운영이 무너지지 않게 합니다

  • 키별 직렬화와 전체 동시성 한도를 함께 둡니다. 같은 고객의 업무는 순서대로 처리하되 서로 다른 고객은 제한 범위 안에서 병렬로 실행할 수 있습니다.
  • queue_depth뿐 아니라 oldest_item_age를 봅니다. 건수는 적어도 오래된 한 건이 계속 밀리고 있을 수 있습니다.
  • 최신 결과만 의미가 있다면 같은 키의 대기 요청을 합칩니다. 오래된 미리보기나 보고서 요청을 모두 실행할 이유는 없습니다.
  • 업무를 버릴 수 없다면 대기열 상한에 도달했을 때 입력을 늦추거나 별도 보관소로 넘깁니다. 조용히 삭제하지 않습니다.
  • 우선순위는 고객 영향과 마감으로 정합니다. 단순히 늦게 들어온 요청이 계속 앞서면 오래된 업무가 영원히 실행되지 않을 수 있습니다.

업무 시나리오별로 정책을 다르게 둡니다

매일 만드는 영업 보고서

조직과 날짜를 키로 잡습니다. 같은 날짜의 실행이 진행 중이면 새 요청은 최신 한 건만 대기시키고, 완료된 결과가 있으면 그 상태와 링크를 돌려줍니다.

고객 문의를 분류하고 CRM을 수정하는 Agent

고객 또는 대화 스레드별로는 순서를 지키고, 서로 다른 고객은 병렬로 처리합니다. CRM API 전체에는 별도 동시성 한도를 두어 한 고객의 폭주가 시스템 전체를 막지 않게 합니다.

RAG 지식 인덱스를 갱신하는 작업

데이터 소스와 버전을 키로 둡니다. 새 버전이 오면 아직 공개되지 않은 옛 계산은 교체할 수 있지만, 공개 전환 단계는 원자적으로 처리하고 이전 인덱스로 되돌릴 경로를 남깁니다.

동시 실행 제어가 무너지는 흔한 이유

  • 프로세스 메모리의 boolean 플래그만 사용합니다. 서버가 여러 대이거나 재시작되면 다른 워커가 그 값을 볼 수 없습니다.
  • 락에 만료가 없습니다. 소유 워커가 죽으면 사람이 직접 지울 때까지 같은 업무가 영구적으로 멈춥니다.
  • 만료만 있고 소유자 검증이 없습니다. 늦게 끝난 워커가 다른 워커가 새로 얻은 락을 지울 수 있습니다.
  • 모든 업무를 하나의 전역 키로 잠급니다. 충돌하지 않는 고객과 문서까지 순서대로 기다립니다.
  • 대기열을 무제한으로 엽니다. 장애가 끝난 뒤 오래된 요청이 한꺼번에 실행되어 다시 외부 API를 압박합니다.
  • 기존 실행을 취소했다고 표시만 하고 하위 도구 호출은 계속 둡니다. 화면에는 취소로 보이지만 실제 메일·CRM 수정은 뒤늦게 일어날 수 있습니다.

운영 대시보드에서 볼 지표

  • overlap_attempt_total: 같은 키로 실행이 겹친 횟수와 적용된 Allow·Skip·Queue·Replace 정책
  • lock_wait_duration과 acquisition_failed_total: 락 대기 시간과 획득 실패 원인
  • queue_depth와 oldest_item_age: 대기 건수와 가장 오래 기다린 업무의 나이
  • active_concurrency와 configured_limit: 현재 실행 수와 설정 한도의 차이
  • lease_renew_failed와 stale_recovery_total: 리스 갱신 실패와 만료 뒤 복구 횟수
  • duplicate_side_effect_total: 동시 실행 제어 뒤에도 실제 메일·레코드·결제가 중복된 건수

임계값은 보편적인 숫자로 복사하지 않습니다. 정상 시간대의 대기 시간과 처리량을 먼저 측정하고, 고객 마감과 외부 API 한도에 맞춰 경보·감속·중지 기준을 정합니다.

배포 전 동시 실행 제어 체크리스트

같은 업무를 판별하는 키에 고객·업무 종류·대상 자원·시점 또는 버전이 필요한 만큼 포함되어 있다.
겹친 요청에 적용할 Allow·Skip·한 건 대기·전체 대기·Replace 정책과 선택 이유가 문서화되어 있다.
공유 저장소의 원자적 선점 방식과 락 소유자 토큰, 만료, 갱신, 해제 조건이 정해져 있다.
같은 키 10건을 동시에 보내도 정책대로 실행 수와 최종 부수효과가 제한된다.
락 획득 직후와 외부 API 호출 중 워커를 강제 종료해도 만료 뒤 복구되며 오래된 워커가 새 소유권을 지우지 못한다.
대기열 상한, 최대 대기 시간, 우선순위, 최신 요청 합치기, 포화 시 입력 처리 기준이 있다.
취소된 실행이 하위 도구까지 멈추거나 안전한 중단 지점에서 종료되는지 확인했다.
겹침·락 대기·대기열 나이·동시 실행 수·리스 실패·중복 부수효과를 운영 화면과 알림에서 확인할 수 있다.

자주 묻는 질문

Q. 멱등성만 구현하면 동시 실행 락은 없어도 되나요?

항상 그렇지는 않습니다. 멱등성이 최종 부수효과 중복을 막더라도 여러 실행이 모델 비용과 외부 API 한도를 함께 쓰고, 서로 다른 시점의 데이터를 계산할 수 있습니다. 실행 경합이 비싸거나 순서가 중요하면 동시 실행 정책이 따로 필요합니다.

Q. 분산락을 위해 Redis가 반드시 필요한가요?

아닙니다. 하나의 데이터베이스가 실행 상태의 기준이라면 고유 제약, 조건부 UPDATE, 짧은 행 락으로 충분한 경우가 많습니다. 여러 저장소와 워커를 가로지르는 리스가 정말 필요한지부터 확인해야 합니다.

Q. 새 요청이 오면 기존 실행을 항상 취소하는 것이 최신 결과에 유리한가요?

기존 결과가 완전히 쓸모없고 하위 작업까지 안전하게 취소할 수 있을 때만 그렇습니다. 메일 발송이나 외부 레코드 생성이 시작됐다면 교체보다 완료 상태 확인, 멱등성 키, 부분 실패 복구가 먼저입니다.

HeyRatty와 겹쳐도 흔들리지 않는 자동화를 설계하려면

HeyRatty는 Agent를 연결하기 전에 업무 키, 중첩 정책, 실행 상태, 외부 시스템 한도, 취소와 사람 인계 흐름을 함께 정리합니다. 그래야 자동화가 빨라져도 같은 일을 서로 덮거나 조용히 줄을 쌓지 않습니다.

처음부터 분산락 플랫폼을 도입할 필요는 없습니다. 가장 자주 겹치는 자동화 한 가지를 골라 '무엇이 같은 업무인지', '두 번째 요청은 기다릴지 버릴지', '첫 실행이 죽으면 누가 이어받을지'부터 적어보세요. 현재 흐름이 복잡하다면 HeyRatty가 작은 파일럿 범위부터 함께 정리할 수 있습니다.


참고 및 이미지 출처

Need AX Partner?

우리 회사 업무에도 AI 자동화를 붙일 수 있을지 궁금하다면

현재 업무 흐름과 데이터 구조를 먼저 보고, 자동화 가능한 구간과 사람이 판단해야 하는 구간을 함께 정리해드립니다.

AX 자동화 상담하기