ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Cloudflare Queues][운영] DLQ replay를 push consumer와 pull consumer에서 어디부터 다르게 점검하나
    기타개발지식/풀스택개발 2026. 8. 11. 20:14

    IT 리서치 노트

    [Cloudflare Queues][운영] DLQ replay를 push consumer와 pull consumer에서 어디부터 다르게 점검하나

    Cloudflare Queues DLQ replay를 운영할 때 많은 팀이 '메시지를 다시 넣는다'는 한 문장으로 끝낸다. 하지만 2026년 8월 11일 기준 Cloudflare 공식 문서를 다시 보면 push consumer는 MessageBatch disposition 기록이 먼저고, pull consumer는 lease_id와 visibility timeout 유효성이 먼저다. 이 글은 DLQ replay를 push consumer와 pull consumer에서 어디부터 다르게 점검하는 편이 실제 복구 시간을 줄이는지 정리한 것이다.

    1. 개요

    결론부터 말하면 push consumer replay는 message disposition과 batch disposition을 먼저 보고, pull consumer replay는 lease_id와 visibility timeout을 먼저 본다. 둘 다 공통으로는 idempotency key와 backlog·message operations 기준선을 같이 남겨야 한다.

    즉 replay runbook은 consumer 종류가 바뀌면 첫 질문도 바뀐다. push는 '무엇을 이미 ack했는가'가 먼저고, pull은 '이 lease가 아직 유효한가'가 먼저다.

    2. 어디서 실제로 막히는가

    현장에서 자주 꼬이는 실수는 네 가지다. 첫째, push와 pull을 같은 replay 버튼처럼 생각해 메모를 한 장으로 쓴다. 둘째, push consumer에서 이미 ack된 sibling message까지 batch째로 다시 재주입한다. 셋째, pull consumer에서 오래된 lease_id를 믿고 재처리 결정을 이어 간다. 넷째, replay 전 backlog와 message operations 기준선을 조회하지 않아 replay 부작용과 원래 적체를 구분하지 못한다.

    Cloudflare DLQ 문서는 보관 창과 별도 consumer 구성을, JavaScript API 문서는 MessageBatch 조작을, pull consumer 문서는 lease_id와 acknowledgement 수명을, metrics 문서는 backlog와 message operations를 설명한다. 이 문서들을 한 줄로 섞으면 '같은 메시지를 다시 넣을까'만 남고, 실제로는 훨씬 중요한 consumer type 분기가 사라진다.

    실무에서는 replay 전에 console에서 queue를 열고, consumer type을 확인하고, push면 disposition 로그를 조회하고, pull이면 lease_id와 visibility timeout 메모를 다시 읽고, metrics를 캡처하고, 그다음에 재처리 범위를 줄여야 한다. 이 순서를 생략하면 같은 side effect를 두 번 만들거나, 이미 만료된 pull 증거를 들고 한참 디버깅하게 된다.

    • 증상: replay 뒤 같은 외부 effect가 다시 발생한다.
    • 실패: push와 pull을 같은 checklist로 본다.
    • 막힘: pull consumer인데 lease_id 만료 여부를 안 조회한다.
    • 누락: replay 직전 backlog와 operations 기준선을 안 남긴다.
    증상 먼저 볼 곳 판단 기준
    push replay 뒤 sibling까지 다시 처리된다 ack/retry와 retryAll 기록 이미 ack된 메시지를 제외했는지 본다
    pull replay가 계속 엇나간다 lease_id와 visibility timeout 오래된 lease를 계속 증거로 쓰지 않는다
    원래 적체와 replay 부작용이 섞인다 backlog·operations 기준선 replay 전후 지표 차이를 비교한다

    3. 실무에서 적용하는 순서

    실무에서는 다섯 단계가 가장 짧다. 먼저 queue 설정에서 consumer type을 확인한다. 두 번째로 idempotency key와 원본 side effect를 조회한다. 세 번째로 push면 MessageBatch disposition 로그를, pull이면 lease_id와 visibility timeout 상태를 분리해서 적는다. 네 번째로 backlog와 message operations 기준선을 저장한다. 마지막으로 replay 범위를 줄인 뒤 다시 실행 결과를 비교한다.

    1. consumer type을 먼저 확인한다.
    2. idempotency key와 원본 effect를 조회한다.
    3. push는 disposition, pull은 lease를 따로 적는다.
    4. metrics 기준선을 저장한다.
    5. 작게 replay하고 결과 로그를 다시 본다.
    question_1 = "이 queue는 push consumer인가, pull consumer인가?"
    question_2 = "같은 idempotency key로 이미 성공한 side effect가 있었는가?"
    question_3 = "push라면 어떤 disposition이 먼저 호출됐는가?"
    question_4 = "pull이라면 lease_id가 아직 유효한가?"
    question_5 = "replay 전 backlog와 operations 기준선은 얼마였는가?"

    이 순서대로 보면 replay 자체보다 replay 범위를 줄이는 일에 집중하게 된다. Cloudflare incident에서 진짜 비싼 실수는 늦게 넣었다가 아니라 불필요한 메시지까지 함께 넣었다는 점이다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 실제 자료는 DLQ 보관 규칙 화면이다. replay 비교를 시작할 때도 출발점은 같다. DLQ는 별도 큐이고, 활성 consumer가 없으면 짧은 보관 창 안에서만 남는다.

    Cloudflare Queues DLQ는 재처리 전에 오래 묵혀 두는 저장소가 아니라 짧은 보관 창을 가진 별도 큐다.
    Cloudflare Queues DLQ는 재처리 전에 오래 묵혀 두는 저장소가 아니라 짧은 보관 창을 가진 별도 큐다.

    그래서 push와 pull을 나누기 전에 먼저 지금 메시지가 retention 안에 있는지 확인하고, replay 범위를 줄이는 순서로 메모를 만들어야 한다.

    두 번째 자료는 MessageBatch 조작 화면이다. push consumer replay에서는 보통 이 레이어를 기준으로 ack, retry, retryAll 호출 기록을 다시 본다.

    push consumer replay는 MessageBatch에서 어떤 메서드를 썼는지 복기하는 것부터 시작한다.
    push consumer replay는 MessageBatch에서 어떤 메서드를 썼는지 복기하는 것부터 시작한다.

    즉 push 쪽은 lease 수명보다 batch disposition 기록이 먼저다. replay 전후에 어떤 메시지를 ack했고 어떤 메시지를 retry했는지 먼저 조회하고, 그다음 재주입 범위를 줄여야 한다.

    세 번째 자료는 pull consumer의 lease_id 화면이다. pull 기반 replay는 message body보다 먼저 이 lease가 아직 유효한지, visibility timeout이 이미 지났는지부터 다시 본다.

    pull consumer replay는 idempotency key와 함께 lease_id 유효성까지 다시 확인해야 한다.
    pull consumer replay는 idempotency key와 함께 lease_id 유효성까지 다시 확인해야 한다.

    push와 가장 크게 갈리는 지점이 여기다. pull은 오래된 lease를 들고 있어도 더 이상 같은 메시지를 제어할 수 없으므로, replay 메모에서 consumer type과 lease_id를 따로 적어야 한다.

    네 번째 실제 자료는 queue metrics다. push든 pull이든 replay 전에는 backlog, message operations, consumer concurrency 기준선을 먼저 캡처해 두는 편이 좋다.

    replay 전후 비교는 메시지 본문만이 아니라 backlog와 operations 기준선까지 같이 남겨야 한다.
    replay 전후 비교는 메시지 본문만이 아니라 backlog와 operations 기준선까지 같이 남겨야 한다.

    이 기준선이 없으면 replay 부작용과 원래 적체를 같은 원인으로 적게 된다. 따라서 metrics를 먼저 조회하고, 값이 튀는 시점을 기록하고, 그다음에 replay를 눌러야 한다.

    실무에서는 replay를 'consumer 종류별로 다른 체크리스트'로 고정하는 편이 빠르다. push는 disposition, pull은 lease와 visibility, 둘 다 idempotency와 metrics를 본다는 공통점까지 한 표로 묶었다.

    Cloudflare Queues DLQ replay를 push consumer와 pull consumer로 나눠 읽는 비교표다.
    Cloudflare Queues DLQ replay를 push consumer와 pull consumer로 나눠 읽는 비교표다.

    이미 DLQ replay 전 체크리스트 글을 읽었다면 이번 표는 그 체크리스트를 consumer 종류 기준으로 다시 나누는 허브판이다. 앞선 explicit ack triage 글과도 자연스럽게 이어진다.

    마지막 자료는 replay 메모 예시다. 클릭 전에 어떤 값을 조회하고, 어떤 값을 입력하고, 어떤 결과 로그를 다시 확인할지 분리해서 적는 편이 좋다.

    push와 pull을 나눠 남기는 DLQ replay 메모 예시다.
    push와 pull을 나눠 남기는 DLQ replay 메모 예시다.

    이 정도 메모만 있어도 같은 메시지를 통째로 다시 넣을지, pull lease부터 다시 조회할지, metrics 기준선을 먼저 볼지 결정이 빨라진다.

    5. 주의사항과 리스크

    첫 번째 리스크는 push consumer에서 이미 ack된 메시지까지 batch째로 다시 넣는 것이다. 두 번째는 pull consumer에서 lease 수명이 끝난 뒤에도 같은 lease_id를 근거로 재처리 판단을 이어 가는 것이다. 세 번째는 replay 전 metrics 기준선을 저장하지 않아 원래 backlog와 replay 부작용을 같은 원인으로 적는 것이다.

    운영 메모에는 최소한 consumer type, idempotency key, disposition 또는 lease, replay 전 backlog, replay 전 message operations가 있어야 한다. 'DLQ에 쌓였음' 한 줄로는 재처리 범위를 줄일 수 없다.

    • push와 pull을 같은 runbook으로 적지 않는다.
    • lease 만료 여부를 replay 뒤가 아니라 replay 전에 본다.
    • metrics 기준선 없이 재처리 버튼을 누르지 않는다.

    6. 결론

    Cloudflare Queues DLQ replay는 consumer 종류가 바뀌면 첫 체크포인트도 바뀐다. push는 disposition과 sibling ack 여부를 먼저 보고, pull은 lease_id와 visibility timeout을 먼저 본 뒤, 둘 다 idempotency key와 metrics 기준선을 함께 남기는 편이 가장 안전하다.

    재처리 전 분기를 정리했다면 그다음 운영 포인트는 replay 직후 지표를 어떤 시간축으로 읽을지다. 후속으로 DLQ replay 전후 backlog recovery와 message operations spike를 어느 시간축으로 비교할지 정리한 글까지 이어 보면 재처리 전 체크와 재처리 후 metrics 해석을 한 runbook 안에 묶기 쉽다.

    • push는 MessageBatch disposition이 먼저다.
    • pull은 lease_id와 visibility timeout이 먼저다.
    • 둘 다 idempotency key와 metrics 기준선을 같이 남긴다.

    7. 참고 링크

    1. https://developers.cloudflare.com/queues/configuration/dead-letter-queues/
    2. https://developers.cloudflare.com/queues/configuration/javascript-apis/
    3. https://developers.cloudflare.com/queues/configuration/pull-consumers/
    4. https://developers.cloudflare.com/queues/observability/metrics/
    5. https://developers.cloudflare.com/queues/configuration/batching-retries/
Designed by Tistory.