
상주 AI 에이전트의 야간 배치(Nightly Batch)를 멱등하게 설계하기
요약
상주형 AI 에이전트의 야간 배치 작업 시 발생할 수 있는 중복 실행 및 실패 문제를 해결하기 위한 멱등성 설계 방안을 다룹니다. 멱등 키와 분산 락을 활용한 구현 패턴과 단계별 체크포인트 설계의 중요성을 설명합니다.
핵심 포인트
- 야간 배치는 최소 1회 실행 보장(at-least-once)을 전제로 설계해야 함
- 멱등 키는 난수가 아닌 결정적인 값(언제, 무엇을, 누구에게)으로 생성해야 함
- DynamoDB의 조건부 쓰기를 활용해 분산 락을 구현할 수 있음
- 파이프라인 단계별 체크포인트를 설계하여 부분 실패 시 복구 효율을 높임
채팅에 상주하며 "밤사이에 로그나 의사록을 수집하여 아침에 리포트를 제출하는" AI 에이전트를 운용하다 보면, 조만간 야간 배치(Nightly Batch)의 실패에 직면하게 됩니다. LLM API의 타임아웃, 외부 연동 대상(Slack/Teams/캘린더 등)의 레이트 리밋(Rate Limit), Lambda의 재시도——원인은 다양하지만, 공통적으로 발생하는 것은 "같은 작업이 2번 실행됨" 또는 "처리 도중에 중단됨"과 같은 상황입니다. 이 기사에서는 상주 에이전트의 야간 배치를 **멱등(idempotent)**하게 설계하기 위한 사고방식과 구현 패턴을 정리합니다.
왜 야간 배치는 「실패를 전제」로 설계해야 하는가
야간 배치는 인간의 눈이 닿지 않는 시간대에 동작합니다. 요청 기반(Request-driven)의 챗봇이라면 실패하더라도 사용자가 다시 말을 걸면 그만이지만, 야간 배치는 "동작했을 텐데 동작하지 않았다"는 사실을 다음 날 아침까지 아무도 알아차릴 수 없습니다.
게다가 클라우드 환경의 작업 실행 기반(EventBridge + Lambda, Step Functions, ECS Scheduled Task 등)은 기본적으로 at-least-once(최소 1회 실행 보장)를 전제로 합니다. 네트워크 순단이나 Lambda의 내부 재시도(Retry)로 인해 동일한 작업이 의도치 않게 2번 기동되는 일은 드물지 않습니다.
즉, 설계자가 해야 할 일은 "실패하지 않도록 하는 것"이 아니라, "몇 번을 실행하더라도 결과가 동일하게 되도록 하는 것"입니다.
멱등성의 3가지 레벨
상주 에이전트의 배치 처리는 다루는 데이터의 성질에 따라 요구되는 멱등성의 레벨이 달라집니다.
| 레벨 | 내용 | 예 |
|---|---|---|
| 1. 자연 멱등 | 처리 그 자체가 재실행해도 동일한 결과가 됨 | "어제의 Slack 로그를 취득하여 요약한다"를 매번 전체량 재취득하기만 하는 처리 |
| ... |
레벨 1로 해결된다면 가장 심플합니다. 하지만 상주 에이전트의 핵심 기능인 "리포트 게시", "외부 시스템으로의 쓰기"는 부작용(Side effect)을 동반하기 때문에, 많은 경우 레벨 2 이상이 필요합니다.
구현 패턴: 멱등 키와 분산 락
레벨 2의 정석적인 구현은, **멱등 키(idempotency key)**를 작업 기동 시에 발행하고 실행 결과와 함께 영속화하는 방법입니다.
key = sha256(job_type + target_date + tenant_id)
if dynamodb.get_item(key) exists and status == "done":
return # 이미 완료됨. 아무것도 하지 않음
...
포인트는 3가지입니다.
- 키는 「언제・무엇을・누구에게」로부터 결정적으로 만들 것(난수나 타임스탬프를 포함하지 않음). 동일한 작업이라면 몇 번을 호출되어도 같은 키가 되어야 합니다.
- 프로세스가 비정상 종료되어 락(Lock)이 계속 남아 있으면, 정당한 재실행까지 차단해 버리므로
in_progress상태에 TTL을 붙입니다. - 실패는 재시도해도 되지만, 성공은 재시도해서는 안 되므로
done과failed를 구분합니다.
DynamoDB의 조건부 쓰기(ConditionExpression: attribute_not_exists(key))를 사용하면, 여러 인스턴스가 동시에 동일한 작업을 가져가려 해도 한쪽만 성공하기 때문에 분산 락(Distributed Lock)으로 그대로 사용할 수 있습니다.
부분 실패로부터의 복구: 체크포인트 설계
「수집 → 요약 → 마스킹 → 게시」와 같이 여러 단계가 있는 파이프라인에서는, 중간 단계에서 실패했을 때 처음부터 다시 시작할지, 실패한 단계부터 재개할지를 결정해 두어야 합니다.
- 수집 단계(외부 API 호출)는 대체로 비용이 높고 레이트 리밋(Rate Limit)도 있음 → 재시도는 피하고 싶음
- 요약 단계(LLM 호출)는 비용이 발생함 → 동일한 입력이라면 재실행해도 결과는 거의 같지만, 과금은 이중으로 되고 싶지 않음
- 게시 단계(Slack/Teams로의 쓰기)는 부작용이 큼 → 반드시 이중 실행을 피해야 함
이 때문에 각 단계의 완료 시점에 중간 결과를 저장해 두고, 실패한 단계에서부터만 재개하는 설계가 현실적입니다. Step Functions와 같은 워크플로우 엔진을 사용하는 경우, 각 상태(State)의 실행 결과가 그대로 영속화되므로 재시도 설정(Retry / Catch)과 조합하는 것만으로 이 구조를 자연스럽게 얻을 수 있습니다. 자체 구현의 경우에도 「단계 이름 + 입력 해시」를 키로 하여 중간 결과를 S3나 DynamoDB에 두는 것만으로도 동일한 효과를 낼 수 있습니다.
요약
- 야간 배치(Nightly Batch)는 at-least-once 실행을 전제로 함. "실패하지 않는 설계"가 아니라 "몇 번을 실행해도 망가지지 않는 설계"를 목표로 함
- 부작용(Side effect)을 동반하는 처리(게시·쓰기)는 멱등 키(Idempotency key) + 조건부 쓰기(Conditional write)를 통해 중복 실행을 방지함
- 다단계 파이프라인은 스텝(Step) 단위로 체크포인트(Checkpoint)를 가져 부분 재개가 가능하도록 함
야간에 자동으로 채팅·메일·캘린더를 수집하여 아침에 리포트로 전달하는 HACH와 같은 에이전트를 만들거나 운영할 경우, 이 "멱등성 (Idempotency)" 설계는 화려하지는 않지만 가장 효과적입니다. 비슷한 상주형 AI 에이전트를 설계하고 계신 분들께 참고가 되기를 바랍니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기