이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- 어떤 AI 기능은 동기 API로 두고 어떤 기능은 worker로 분리해야 하는가?
- 비동기 job 처리에서 idempotency와 상태 관리가 왜 중요한가?
- API 서버와 worker 사이 계약은 어떻게 잡아야 하는가?
개요
AI 작업은 처리 시간이 예측하기 어렵다. 짧은 분류는 동기 API로 충분하지만, 긴 문서 처리와 RAG 색인, agent workflow는 비동기 worker로 분리해야 API 서버를 보호할 수 있다.
동기 API 기준
동기 처리에 적합한 경우:
- 짧은 입력
- 짧은 출력
- 3초에서 8초 안에 끝남
- 실패 시 바로 재시도 가능
- side effect 없음
예: 짧은 문의 분류, 간단한 문장 교정, 짧은 요약.
비동기 Worker 기준
worker에 적합한 경우:
- 긴 문서
- batch embedding
- eval
- RAG indexing
- agent workflow
- 파일 처리
- 여러 tool 호출
이 경우 API는 job id를 반환하고 상태 조회를 제공한다.
코드로 이해하기
job 상태를 명확히 둔다.
public enum AiJobStatus {
QUEUED,
RUNNING,
COMPLETED,
FAILED,
CANCELLED
}
public record AiJobMessage(
String jobId,
String tenantId,
String userId,
String traceId,
String promptVersion,
String idempotencyKey
) {
}상태 전이가 있어야 retry와 중복 실행을 관리할 수 있다.
Worker 안정성
worker는 다음을 가져야 한다.
- concurrency limit
- idempotency key
- DLQ
- retry policy
- job timeout
- cancellation
- result storage
- trace propagation
queue 메시지는 중복 전달될 수 있다고 가정한다.
장애 상황과 대응
증상:
- API timeout 증가
- queue depth 증가
- 같은 job 두 번 실행
- DLQ 증가
- worker가 provider rate limit을 초과
대응:
- worker concurrency 조정
- backpressure 적용
- idempotency 확인
- batch와 online queue 분리
- DLQ 재처리 runbook 작성
인프라 협업 포인트
인프라팀과는 queue, worker autoscaling, rate limit, DLQ, job retention, streaming timeout을 합의한다.
개인 프로젝트 최소 기준
- 긴 작업은 background job으로 뺀다.
- job status를 DB에 저장한다.
- 실패 이유를 남긴다.
- worker 재시작 후에도 재처리 가능하게 한다.
기업 운영 수준 기준
- queue depth와 job age 알림을 둔다.
- worker pool을 workload별로 분리한다.
- DLQ와 재처리 절차를 둔다.
- tenant별 concurrency 제한을 둔다.
실전 팁
- provider retry와 queue retry가 겹치지 않게 한다.
- job payload에는 원문보다 resource id를 넣는다.
- 사용자가 취소한 job은 worker가 확인할 수 있게 한다.
- 결과 저장은 idempotent하게 만든다.
위험 신호!
- 긴 AI 작업이 동기 Controller에서 실행된다.
- job 상태가 없다.
- queue 중복 전달을 고려하지 않는다.
- DLQ가 있지만 모니터링하지 않는다.
확인 질문
확인 질문
- queue worker가 idempotency를 가져야 하는 이유는 무엇인가?
- 메시지가 중복 전달되거나 retry될 수 있기 때문이다.
- AI 작업을 비동기로 분리하는 가장 큰 이유는 무엇인가?
- API 서버 리소스와 사용자 요청 흐름을 긴 작업에서 보호하기 위해서다.