-
[Cloudflare Queues][운영] consumer batch에서 ack·retry·retryAll을 poison message와 DLQ 기준으로 언제 나누나기타개발지식/풀스택개발 2026. 8. 7. 20:20
IT 리서치 노트
[Cloudflare Queues][운영] consumer batch에서 ack·retry·retryAll을 poison message와 DLQ 기준으로 언제 나누나
Cloudflare Queues consumer를 붙인 뒤 많은 팀이 실패 메시지를 모두 같은 재시도 정책으로 처리한다. 하지만 2026년 8월 7일 기준 Cloudflare 공식 문서를 다시 보면
ack(),retry(), batch 재시도, DLQ는 서로 다른 손잡이다. 이 글은 consumer batch에서 ack·retry·retryAll을 poison message와 DLQ 기준으로 언제 나눠야 하는지 정리한 것이다.1. 개요
결론부터 말하면 정상 처리 완료 메시지는 먼저
ack()로 떼고, 일시적 오류는retry()로 개별 backoff를 붙이고, 문제 메시지를 아직 분리하지 못한 짧은 완충 상태에서만retryAll()을 쓰는 편이 맞다. 영구 오류나 유실 불가 메시지는 DLQ 기준으로 본다.즉 이 문제는 retry 숫자만의 문제가 아니라 batch 안 메시지 분류 문제다. poison message를 가르지 못한 상태를 오래 끌수록 전체 batch 재시도와 read 비용이 같이 커진다.
2. 어디서 실제로 막히는가
실무에서 자주 꼬이는 지점은 세 가지다. 첫째, 성공 메시지까지 ack하지 않아 poison message와 함께 다시 돈다. 둘째, 일시적 429와 영구 데이터 오류를 같은
retryAll()로 묶는다. 셋째, DLQ를 붙여야 할 영구 오류를 retry 숫자만 늘려서 해결하려 한다.Cloudflare 문서는 메시지별 ack와 retry를 제공하고, batching guide는 ack되지 않은 메시지가 함께 재시도될 수 있음을 설명한다. DLQ 문서는 최종 실패 메시지의 보존 경로를 별도로 둔다. 이 셋을 같이 읽으면 메서드 선택을 숫자 조정보다 먼저 해야 한다는 점이 분명해진다.
운영에서 오래 막히는 이유는 개발자가 실패를 '재시도 여부' 한 가지 질문으로만 보기 때문이다. 실제로는 처리 완료 메시지를 먼저 ack로 분리하고, 429와 timeout을 retry로 분리하고, payload가 깨진 영구 오류를 DLQ 후보로 분리하고, 그 뒤에야 retryAll이 정말 필요한지 판단해야 한다. 이 분리 순서를 코드와 로그와 알람에서 동시에 지키지 않으면 같은 batch 실패가 다음 주에도 같은 모양으로 반복된다.
- 증상: 한 건 실패 때문에 정상 메시지까지 반복 처리된다.
- 실패: ack 없이 batch 전체 재시도를 오래 유지한다.
- 막힘: 429와 poison message를 같은 경로로 처리한다.
- 누락: 유실 불가 메시지의 DLQ 기준을 코드 밖에만 적어 둔다.
3. 실무에서 적용하는 순서
운영 순서는 네 단계가 가장 짧다. 먼저 성공 메시지를 ack로 분리한다. 두 번째로 일시 오류는 개별 retry와 delay로 보낸다. 세 번째로 어떤 메시지가 문제인지 아직 모를 때만 retryAll을 짧게 쓰고, 곧바로 분리 로직을 추가한다. 마지막으로 영구 오류와 유실 불가 메시지는 DLQ 기준과 함께 기록한다.
- 성공 메시지는 먼저 ack로 분리한다.
- 일시 오류는 retry와 delay를 붙인다.
- retryAll은 짧은 완충용으로만 쓴다.
- 영구 오류는 DLQ와 재처리 메모로 넘긴다.
실제 점검에서는 worker 로그를 열고, batch 안 message id를 적고, 성공 메시지를 먼저 ack 처리하고, 429 메시지는 retry delay와 attempts를 기록하고, poison message 후보는 body와 error kind를 저장하고, DLQ 전송 여부를 확인하고, 재시도 후 상태를 다시 조회하는 편이 좋다. 숫자를 바꾸기 전에 먼저 어떤 메시지가 왜 그 메서드로 갔는지 남겨야 한다. 운영자는 message id를 비교하고, 알람을 분리하고, 재현 쿼리를 만들고, DLQ consumer를 준비하고, 다음 배포에서 같은 분기표가 유지되는지 다시 확인해야 한다.
batch_id=... ack_count=9 retry_count=1 retryall_used=false poison_message_detected=true dlq_needed=true4. 공식 문서와 예시 화면으로 확인하기
첫 공식 화면은 메시지별
ack()구간이다. 이 메서드는 이미 성공한 메시지를 현재 batch 재시도 바깥으로 빼는 기준점이 된다.즉 poison message가 batch 안에 섞여 있어도 정상 메시지까지 같이 끌고 가야 하는 것은 아니다. 먼저 ack 가능한 메시지를 분리해 두면 retry 정책이 훨씬 짧아진다.
두 번째 자료는 개별
retry()구간이다. 일시적 외부 API 오류처럼 재시도 가치가 있는 메시지는 batch 전체가 아니라 메시지 단위로 다시 보내는 편이 맞다.이 문장을 기준으로 보면 429나 짧은 downstream 장애는 ack와 retry를 함께 섞어 처리하는 편이 낫다. 모든 실패를 retryAll로 올리는 것은 대체로 과하다.
세 번째 화면은 batch 단위 재시도 개념이다. handler 예외나
retryAll()은 아직 ack되지 않은 나머지 메시지를 한 번에 다시 보내는 선택이다.그래서 retryAll은 poison message를 세밀하게 가를 때보다, 아직 어떤 메시지가 문제인지 분리하기 전 짧은 장애 흡수용으로 보는 편이 맞다. 원인 미분류 상태를 오래 유지하면 read 비용과 재처리량이 같이 오른다.
네 번째 자료는 DLQ 자체다. max retries를 모두 소모한 메시지는 DLQ로 보낼 수 있고, DLQ가 없으면 영구 삭제될 수 있다.
즉 poison message가 반복적으로 실패하는 경로라면 retryAll을 길게 끌기보다 DLQ로 보내 원인 분석이나 수동 재처리를 하는 편이 낫다. 중요 메시지 경로에서는 이 보존 여부가 숫자 튜닝보다 먼저다.
실무에서 필요한 것은 메서드 선택 기준표다. 같은 batch 실패라도 어떤 것은 ack, 어떤 것은 retry, 어떤 것은 retryAll, 어떤 것은 DLQ로 가야 한다.
이미 retry 3회 기본값과 DLQ 글이 숫자 정책을 다뤘다면, 이번 표는 consumer 코드 안에서 어떤 메서드를 먼저 고를지의 후속편이다.
마지막 자료는 batch handler 예시다. 정상 메시지는 ack하고, 일시 오류는 retry하며, 영구 오류는 DLQ 기준으로 남기는 흐름을 한 번에 적었다.
핵심은 모든 실패를 같은 메서드로 처리하지 않는 것이다. poison message를 따로 가르기 시작하면 retryAll은 점점 줄고, ack와 retry와 DLQ 경로가 더 분명해진다.
5. 주의사항과 리스크
첫 번째 리스크는 retryAll을 기본 선택처럼 쓰는 것이다. 두 번째는 ack를 늦게 해 정상 메시지까지 재처리시키는 것이다. 세 번째는 poison message를 오래 retry하다가 DLQ 기준을 뒤늦게 붙이는 것이다.
운영 전에 확인할 때는 acked messages, retried messages, retryAll 사용 여부, DLQ 전송 기준을 같은 표에 두는 편이 좋다. 이 네 칸이 없으면 batch 처리 구조 판단이 계속 늦어진다.
6. 결론
Cloudflare Queues consumer batch에서는 모든 실패를 같은 재시도 경로로 몰지 않는 편이 맞다. 먼저 ack로 정상 메시지를 떼고, 일시 오류는 retry로 좁히고, retryAll은 짧게만 쓰고, 영구 오류는 DLQ 기준으로 분리하면 poison message 때문에 전체 batch가 흔들리는 시간을 줄일 수 있다.
이 분기표를 적용한 뒤 consumer concurrency를 높였는데 duplicate 해석이 길어진다면, 후속편인 consumer concurrency 확대 시 duplicate 처리와 idempotency key 로그를 어떤 순서로 남길지 정리한 글로 이어서 보는 편이 좋다. 메서드 선택 다음 단계는 로그 구조와 key 검증 순서를 고정하는 일이다.
- ack는 성공 메시지 분리용이다.
- retry는 개별 일시 오류용이다.
- retryAll은 오래 끌지 말고 DLQ 기준과 함께 줄여 간다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글