AI 콘텐츠 생성 재시도 설계: 작업 상태로 중복 실행 막는 기준
“생성 요청이 실패했을 때 다시 돌리면 같은 글이 두 번 만들어질까 봐 걱정됩니다.”
“큐 메시지가 다시 들어왔는데, 이전 작업이 정말 끝난 것인지 알기 어렵습니다.”
“실패한 작업만 골라 재시도하고 싶은데 운영 화면에서는 상태가 뒤섞여 보입니다.”
재시도와 중복 방지는 별개 기능이 아니라 하나의 논리 작업이 어떤 상태에 있으며 누가 실행 권한을 갖는지 기록하는 문제입니다. AI 콘텐츠 생성 파이프라인은 큐 메시지 자체가 아니라 영속화된 작업 레코드를 기준으로 재실행 여부를 판단해야 합니다.
알레오 같은 AI 검색과 블로그 SaaS를 설계할 때도 생성 요청, 외부 모델 호출, 결과 저장, 게시 준비를 한 번의 처리로 묶지 않는 편이 중요합니다. 서비스 아키텍처와 백엔드, DB 설계 및 운영을 맡아 온 권승현의 관점에서는 각 단계의 완료 조건과 다음 실행 조건을 분리해야 원인을 추적하고 롤백 범위도 정할 수 있습니다.
재시도는 왜 작업 상태를 기준으로 해야 할까요?

큐 메시지는 실행을 촉발하는 신호로 두고, 재시도 여부와 결과의 정합성은 영속화된 작업 상태로 결정해야 합니다. 그래야 같은 메시지가 다시 전달되거나 워커가 중간에 멈춰도 이미 끝난 작업과 다시 실행할 작업을 구분할 수 있습니다.
AI 콘텐츠 생성에는 보통 다음 구간이 있습니다.
- 사용자의 생성 요청을 접수한다.
- 생성에 필요한 입력과 정책을 고정한다.
- 모델 호출과 초안 생성을 수행한다.
- 결과를 저장하고 후속 검수나 게시 흐름으로 넘긴다.
이 과정을 큐 소비 한 번의 성공 또는 실패로만 기록하면 복구 지점이 사라집니다. 모델 응답을 받았지만 결과 저장 전에 워커가 종료될 수 있고, 결과를 저장했지만 메시지 확인 전에 처리가 끊길 수도 있습니다. 이때 실패만 보고 다시 실행하면 이미 생성된 결과를 덮어쓰거나 초안을 하나 더 만들 수 있습니다.
Google Cloud Spanner 큐 문서는 at-least-once 전달에서 네트워크 오류가 발생하면 동일 메시지가 여러 번 전송되고 처리될 수 있다고 설명합니다.
소비자가 처리를 마치기 전 종료되거나 메시지를 확인하지 못한 경우에도, 해당 제품에서는 리스 만료 뒤 재시도를 위해 메시지가 다시 전송될 수 있습니다.
따라서 사용하는 큐의 전달과 확인 규칙을 확인한 뒤, 소비자는 동일 논리 작업의 재수신을 전제로 설계하는 편이 안전합니다.
상태는 처리 로그가 아니라 판단 기준입니다

상태 필드는 단순히 성공과 실패를 남기는 로그가 아닙니다. 운영자와 워커가 다음 행동을 결정하기 위한 계약입니다. 다음은 콘텐츠 생성 작업에 적용할 수 있는 예시입니다.
| 상태 | 의미 | 다음 판단 |
|---|---|---|
requested | 생성 요청이 등록됨 | 큐에 전달할 수 있음 |
running | 한 실행자가 처리 권한을 가짐 | 중복 실행을 막고 만료 여부를 확인 |
retry_wait | 재시도 조건을 기다림 | 지정 시점 이후 다시 실행 |
generated | 생성 결과가 저장됨 | 후속 검수나 게시 단계로 이동 |
succeeded | 정의한 작업 범위가 완료됨 | 같은 작업 키의 재실행을 막음 |
failed | 자동 재시도를 멈춘 실패 | 원인 확인 뒤 수동 재개 여부 판단 |
중요한 것은 상태 이름보다 전이 규칙입니다. running을 언제 retry_wait로 바꿀지, generated 뒤 어떤 조건에서 완료를 인정할지를 먼저 정해야 합니다. 완료된 결과가 있는데도 모델을 다시 호출하는 경로가 남아 있다면 상태를 늘려도 중복 방지는 되지 않습니다.
중복 생성을 막는 작업 키는 어떻게 정해야 할까요?

중복 방지의 출발점은 요청 횟수가 아니라 같은 결과를 위해 수행하는 논리 작업을 식별하는 고정 키입니다. 사용자가 버튼을 두 번 눌렀는지보다 두 요청이 같은 콘텐츠 작업을 뜻하는지 판단할 수 있어야 합니다.
예를 들어 블로그 초안 생성이라면 작업 키에 다음처럼 변하지 않아야 할 식별자를 연결할 수 있습니다.
- 콘텐츠 대상의 식별자
- 생성 목적 또는 워크플로 단계
- 확정된 입력 버전
- 요청을 구분해야 한다면 명시적인 요청 식별자
반대로 실행 시각, 워커 식별자, 재시도 횟수처럼 실행마다 바뀌는 값은 작업 키의 중심에 넣지 않는 편이 낫습니다. 이런 값까지 키를 바꾸면 같은 논리 작업이 재시도될 때마다 새 작업으로 인식될 수 있습니다.
작업 키를 데이터베이스에서 유일하게 관리한다면 생성 요청을 받을 때 기존 레코드를 먼저 확인합니다. 이미 succeeded 상태라면 저장된 결과를 반환하거나 후속 단계로 안내할 수 있습니다. running이면 새 실행보다 진행 중인 작업을 보여 주고, failed이면 오류 원인과 정책에 따라 새 시도를 허용할지 판단합니다.
같은 입력으로 다시 들어온 요청을 새 메시지가 아니라 기존 논리 작업에 다시 접근한 것으로 해석하는 것이 중복 방지의 핵심입니다. 키 생성 규칙, 보관 기간, 동일 키 재사용 시 응답 방식은 데이터 모델과 API 계약에 맞춰 별도로 정해야 합니다.
외부 API 호출처럼 비즈니스 처리와 큐 확인을 원자적으로 결합하기 어려운 작업에서는 외부 작업이 중복 실행될 수 있어 애플리케이션 차원의 멱등성 전략이 필요합니다.
네트워크 오류 뒤에는 서버 측 커밋 성공 여부를 알 수 없는 상태가 생길 수 있으므로, 비멱등 작업을 무조건 재시도하면 부작용이 반복될 위험도 있습니다.
다만 이 근거는 Spanner 큐와 외부 서비스 호출 맥락을 다룬 것으로, 키의 세부 형식까지 정해 주지는 않습니다.
결과 레코드와 작업 레코드는 왜 분리할까요?
작업 레코드는 실행을 관리하고, 결과 레코드는 만들어진 콘텐츠를 관리합니다. 둘을 하나로 합치면 초안이 저장된 사실과 전체 파이프라인이 완료된 사실이 섞입니다.
모델이 만든 본문이 저장됐더라도 검수 대기나 발행 준비가 남았다면 작업 상태를 바로 succeeded로 처리할 이유는 없습니다. 반대로 콘텐츠 결과가 유효하게 저장됐다면 워커 응답이 끊겼다고 해서 모델 호출부터 반복할 필요도 없습니다. 결과 레코드와 작업 상태를 대조해 비어 있는 단계만 이어서 처리하는 경로를 둡니다.
실행 중인 작업이 멈췄는지는 어떻게 판단할까요?
running 상태만으로 실행 중이라고 단정하지 말고, 실행 권한의 만료 시각과 시도 정보를 함께 기록해야 합니다. 워커 장애, 배포, 타임아웃으로 실행자가 사라진 작업은 다른 실행자가 회수할 수 있어야 합니다.
작업을 가져갈 때 실행 소유자와 임대 만료 시각을 함께 갱신하는 방식을 고려할 수 있습니다. 워커가 처리 중이면 만료 시각을 연장하고, 만료 시각이 지난 running 작업만 회수 후보로 봅니다. 회수하는 실행자도 현재 상태와 만료 조건을 다시 확인한 뒤에만 권한을 얻도록 해야 합니다.
임대 시간이 짧다고 복구가 빨라지는 것은 아닙니다. 모델 호출 시간이 길거나 저장 단계가 지연되는 환경에서는 아직 처리 중인 작업을 다른 워커가 가져갈 수 있습니다. 반대로 너무 길면 실제 장애 뒤 복구가 늦어집니다. 제한 시간은 모델 호출, 결과 저장, 외부 API 지연처럼 실제 처리 구간을 나눠 관찰한 뒤 정하는 것이 좋습니다.
권승현은 구현 완료, 로컬 검증, 원격 반영, 배포, 운영 수용을 서로 다른 단계로 구분하는 방식으로 작업해 왔습니다. 이 관점은 비동기 작업에도 적용할 수 있습니다. 워커 함수가 끝났다는 사실만으로 콘텐츠가 운영상 수용 가능한 상태인지 판단하지 않고, 저장 결과와 후속 단계까지 각각 확인하는 방식입니다.
재시도 정책은 무엇을 기록해야 운영할 수 있을까요?
재시도 횟수만 저장하면 부족하며, 실패 원인과 다음 실행 시각, 마지막 실행의 관찰 정보를 함께 남겨야 합니다. 그래야 자동 재시도와 사람이 확인해야 할 실패를 분리할 수 있습니다.
다음 항목은 작업 레코드나 별도 실행 이력에 남길 만합니다.
- 현재 상태와 상태가 바뀐 시각
- 전체 시도 횟수와 마지막 시도 번호
- 다음 재시도 가능 시각
- 실행 소유자 또는 실행 식별자
- 오류 분류와 안전하게 축약한 오류 정보
- 결과 레코드 식별자와 외부 호출 식별자
오류를 모두 같은 방식으로 재시도하면 비용과 혼란이 커집니다. 입력 누락이나 권한 오류처럼 재시도로 해결되지 않는 문제는 failed로 보내고 수정 근거를 남기는 편이 낫습니다. 일시적인 외부 호출 오류처럼 회복 가능성이 있는 문제만 retry_wait로 전환합니다. 어떤 오류가 어느 분류에 속하는지는 모델 API와 서비스 정책에 따라 다르므로, 처음에는 넓게 묶어 관찰하고 실제 기록을 바탕으로 조정해야 합니다.
재시도 전에는 다음 질문을 확인해 보세요.
- 이전 시도가 결과를 이미 저장했는가?
- 동일 작업 키의 다른 실행자가 아직 유효한가?
- 지금 재시도해도 입력 버전과 정책이 같은가?
- 재시도로 해결될 성격의 오류인가?
- 이번 시도의 결과를 기존 결과에 안전하게 연결할 수 있는가?
운영 화면에도 이 판단 근거를 반영할 수 있습니다. 실패라는 상태 하나만 보여 주는 대신 마지막 오류 분류, 다음 재시도 예정, 결과 존재 여부, 수동 조치 필요 여부를 표시하면 불필요한 재실행을 줄이는 데 도움이 됩니다.
상태 전이를 어디까지 작게 나눠야 할까요?
상태는 복구 판단이 달라지는 지점까지만 나누는 것이 좋습니다. 모든 함수 호출을 상태로 만들면 운영 복잡도가 커지고, 중요한 저장 경계를 생략하면 어느 단계부터 다시 시작해야 할지 알 수 없습니다.
처음에는 다음 세 경계를 우선 분리할 수 있습니다.
- 요청이 영속화됐는가
- 생성 결과가 영속화됐는가
- 사용자에게 완료로 제공할 조건을 충족했는가
이 세 경계가 분명하면 큐 전달 실패, 모델 호출 실패, 결과 저장 실패, 후속 발행 단계 실패를 서로 다른 문제로 볼 수 있습니다. 큐 전달이 실패했다면 아직 실행하지 않은 요청을 다시 전달할 수 있지만, 결과 저장 직후 실패했다면 저장된 결과를 확인한 다음 후속 단계만 재개해야 합니다.
Spanner 큐 문서도 장기 실행 작업에서 리스를 연장하거나 후속 메시지를 예약하는 흐름을 제시하며, 성공과 외부 부작용의 결합 방식을 명시할 필요를 보여 줍니다.
이는 일반적인 상태 스키마의 표준은 아니므로, 상태 수와 전이 규칙은 서비스의 복구 지점에 맞춰 정해야 합니다.
대규모 변경을 작은 단계와 승인 지점으로 나누는 방식도 여기에 맞습니다. 먼저 작업 키와 상태 테이블을 도입하고, 다음으로 실행 소유권과 만료 처리를 붙인 뒤, 마지막으로 오류 분류와 운영 화면을 확장합니다. 처음부터 모든 예외를 자동화하기보다 각 단계에서 재현 가능한 실패와 기록을 확인하는 편이 원인 추적에 유리합니다.
결론
AI 콘텐츠 생성 파이프라인의 재시도는 메시지를 다시 넣는 기능이 아니라, 기존 논리 작업을 안전하게 이어서 처리하는 상태 전이로 설계해야 합니다. 작업 키로 같은 일을 식별하고, 상태와 실행 권한으로 중복 실행을 막고, 결과 저장 여부를 확인한 뒤 비어 있는 단계만 재개하세요.
처음 설계를 점검한다면 성공 또는 실패라는 이분법부터 바꾸는 것이 좋습니다. 요청 등록, 실행 중, 결과 저장, 재시도 대기, 완료 불가처럼 복구 판단이 달라지는 경계를 정하고 모든 재시도가 그 상태를 확인하도록 만들면, 운영자가 추측으로 작업을 다시 돌리는 일을 줄일 수 있습니다.
자주 묻는 질문
큐가 중복 메시지를 보내지 않으면 작업 키가 없어도 되나요?
아니요. 큐의 전달 보장과 애플리케이션의 논리 작업 중복은 별도로 다뤄야 합니다. 사용자 요청 중복, API 재전송, 워커 종료 시점은 메시지 전달 방식만으로 모두 해결하기 어려우므로 작업 키와 상태 확인이 필요합니다.
생성 결과를 덮어써도 되는 경우는 언제인가요?
명시적으로 새 버전을 만드는 정책이 있을 때만 덮어쓰기보다 버전 분리를 우선하는 편이 안전합니다. 동일 작업의 복구인지 사용자가 새 입력으로 재생성을 요청한 것인지 구분할 수 있어야 이전 결과의 추적 가능성을 잃지 않습니다.
자동 재시도 횟수는 몇 번으로 정해야 하나요?
고정된 정답은 없으며 오류 유형과 비용, 복구 시간에 맞춰 정해야 합니다. 재시도로 해결되지 않는 입력 및 권한 오류는 빨리 멈추고, 일시적 오류는 다음 실행 시각과 함께 제한적으로 재시도한 뒤 실제 이력을 보고 조정하세요.
상태 테이블을 따로 만들지 않고 콘텐츠 테이블에 상태를 넣어도 되나요?
초기에는 가능하지만, 실행 이력과 콘텐츠 결과의 의미가 달라지면 분리를 검토해야 합니다. 콘텐츠 생명주기와 생성 작업의 실행 생명주기가 섞여 복구 판단이 어려워지는 시점이 분리 기준입니다.
제 도움이 필요하시다면
AI 생성 기능에 큐를 붙였지만 중복 생성, 재시도 기준, 결과 저장 경계가 불분명한 팀이라면 작업 상태와 데이터 계약부터 함께 점검할 수 있습니다. 알레오의 개발 과정에서 다뤄 온 서비스 아키텍처, 백엔드, DB 설계와 운영 관점을 바탕으로 작업 단위 정의, 상태 전이, 검증 순서와 롤백 범위를 구체화하는 데 도움을 드립니다.
여러 저장소와 API 계약이 연결되어 변경 책임이나 통합 순서를 정리해야 하는 경우에도, 기능 구현과 운영 수용을 분리해 확인할 항목을 설계할 수 있습니다. 서비스 범위는 알레오 공식 웹사이트에서 확인할 수 있습니다.
-cropped.png&w=3840&q=75)
