<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Embedded Durable Queue on jyukki's Blog</title><link>https://jyukki.com/tags/embedded-durable-queue/</link><description>Recent content in Embedded Durable Queue on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-kr</language><lastBuildDate>Fri, 01 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jyukki.com/tags/embedded-durable-queue/index.xml" rel="self" type="application/rss+xml"/><item><title>2026 개발 트렌드: Embedded Durable Queue, 워커와 스케줄러를 SQLite·Postgres에 다시 붙이는 팀이 늘어나는 이유</title><link>https://jyukki.com/posts/2026-05-01-embedded-durable-queue-sqlite-postgres-trend/</link><pubDate>Fri, 01 May 2026 00:00:00 +0000</pubDate><guid>https://jyukki.com/posts/2026-05-01-embedded-durable-queue-sqlite-postgres-trend/</guid><description>요즘 팀들이 모든 비동기 작업을 무조건 외부 브로커로 보내기보다, SQLite나 Postgres 위에 durable queue와 scheduler를 다시 올리는 이유를 실무 기준으로 정리합니다.</description><content:encoded><![CDATA[<p>요즘 비동기 아키텍처 얘기를 보면 흥미로운 역류가 하나 있습니다. 몇 년 전까지는 &ldquo;브로커를 붙여야 확장된다&quot;가 거의 상식처럼 통했는데, 최근엔 오히려 <strong>작업 수명주기가 짧고 운영팀 규모가 작은 영역은 SQLite나 Postgres 위로 다시 붙이는 흐름</strong>이 눈에 띕니다. durable queue, retry, cron, lease, replay를 굳이 별도 인프라로 흩뿌리지 않고, 이미 믿고 있는 저장소 안에서 닫아 버리는 쪽이 더 싸고 더 설명 가능하다는 판단이 늘고 있는 겁니다.</p>
<p>이건 단순한 경량화 취향이 아닙니다. 최근엔 SQLite 파일 안에서 queue, stream, pub/sub, scheduler를 묶는 도구나, Postgres를 durable execution/cron 기반으로 쓰는 패턴이 다시 주목받고 있습니다. 배경은 명확합니다. 많은 팀이 브로커를 도입한 뒤에도 결국 <a href="/learning/deep-dive/deep-dive-queue-visibility-timeout-acknack-playbook/">Queue Visibility Timeout·Ack/Nack·DLQ 설계</a>, <a href="/learning/deep-dive/deep-dive-transactional-outbox-cdc/">Transactional Outbox + CDC</a>, <a href="/learning/deep-dive/deep-dive-distributed-scheduler-singleton-playbook/">분산 스케줄러 Singleton 실행 보장</a>, <a href="/learning/deep-dive/deep-dive-reconciliation-ledger-pipeline/">Reconciliation 파이프라인</a> 같은 규율을 다시 구현해야 한다는 사실을 체감했기 때문입니다. 결국 질문은 &ldquo;브로커가 있나 없나&quot;가 아니라, <strong>이 작업을 정말 별도 확장 단위로 분리할 가치가 있나</strong>로 바뀌고 있습니다.</p>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li>왜 작은 팀과 특정 워크로드에서 embedded durable queue가 다시 주목받는지 이해할 수 있습니다.</li>
<li>SQLite/Postgres 기반 queue가 잘 맞는 작업과, 애초에 전용 브로커가 더 나은 작업을 구분할 수 있습니다.</li>
<li><code>queue depth</code>, <code>oldest runnable age</code>, <code>retry inflation</code>, <code>stuck lease</code> 같은 실무 기준을 숫자로 잡을 수 있습니다.</li>
<li>&ldquo;단순화&quot;와 &ldquo;과소설계&quot;를 혼동하지 않도록 경계 조건을 가져갈 수 있습니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-요즘-팀들이-줄이려는-것은-메시징-기능보다-운영-표면적이다">1) 요즘 팀들이 줄이려는 것은 메시징 기능보다 운영 표면적이다</h3>
<p>대부분의 팀은 브로커를 싫어해서가 아니라, <strong>운영해야 할 이동 부품이 너무 많아져서</strong> 피로해집니다. 워커가 조금만 늘어도 아래 문제가 반복됩니다.</p>
<ul>
<li>브로커 backlog와 DB 상태를 따로 봐야 함</li>
<li>retry, DLQ, scheduler, replay가 각자 다른 저장소와 규칙을 가짐</li>
<li>&ldquo;왜 이 작업이 다시 실행됐나&quot;를 시스템 경계마다 추적해야 함</li>
<li>작은 백오피스 작업인데도 infra 무게가 본체보다 커짐</li>
</ul>
<p>그래서 최근 흐름은 기능을 포기하는 게 아니라, <strong>작업 상태와 비즈니스 상태를 같은 저장소에서 더 가깝게 두는 쪽</strong>으로 움직입니다. 이 접근은 특히 관리자 작업, 웹훅 전송, 이메일 발송, 썸네일 생성, 정기 집계, 소규모 workflow에서 강합니다.</p>
<h3 id="2-적합성의-핵심은-tps보다-독립-확장-필요성이다">2) 적합성의 핵심은 TPS보다 독립 확장 필요성이다</h3>
<p>DB queue를 평가할 때 많은 팀이 먼저 초당 처리량부터 봅니다. 물론 중요합니다. 하지만 실무에서는 오히려 아래 질문이 더 먼저입니다.</p>
<ul>
<li>작업 실행을 서비스 read/write 경로와 <strong>독립적으로 확장</strong>해야 하나?</li>
<li>하나의 테넌트 backlog가 다른 테넌트를 심하게 오염시킬 수 있나?</li>
<li>소비 지연을 수 시간, 수일 단위로 버텨야 하나?</li>
<li>fan-out subscriber가 여러 개이며 서로 다른 재처리 정책이 필요한가?</li>
</ul>
<p>이 질문에 &ldquo;그렇다&quot;가 많을수록 전용 브로커나 workflow 엔진 쪽이 낫습니다. 반대로 작업이 단순하고, 상태를 DB에서 바로 읽어야 하며, 운영자가 SQL 한 번으로 재처리 상황을 설명할 수 있어야 한다면 DB queue는 생각보다 강합니다.</p>
<p>시작 기준으로는 아래 정도가 무난합니다.</p>
<ul>
<li>초당 신규 job이 <strong>200~500개 이하</strong></li>
<li>동시 워커가 <strong>10~30개 이하</strong></li>
<li>개별 job 실행 시간이 보통 <strong>수 초 이내</strong></li>
<li>backlog 보존이 <strong>수일~수주</strong> 수준에서 닫힘</li>
<li>fan-out subscriber보다 <strong>단일 소유자 워크플로</strong> 비중이 큼</li>
</ul>
<p>이 수치는 절대값이 아니라 &ldquo;여기까지는 DB 단순성 이점이 자주 더 크다&quot;는 운영 감각에 가깝습니다.</p>
<h3 id="3-db에-붙인다고-해서-큐-규율이-사라지는-것은-아니다">3) DB에 붙인다고 해서 큐 규율이 사라지는 것은 아니다</h3>
<p>여기서 제일 위험한 오해가 있습니다. &ldquo;DB니까 그냥 테이블 한 장이면 되겠지&quot;라는 생각입니다. 그건 거의 항상 사고로 갑니다. DB queue에도 결국 아래 규율이 필요합니다.</p>
<ul>
<li>lease 또는 visibility timeout</li>
<li>idempotency key</li>
<li>retry 횟수와 backoff</li>
<li>poison job 분리</li>
<li>replay reason 기록</li>
<li>oldest runnable age 모니터링</li>
</ul>
<p>즉 최근 트렌드는 큐 규율을 버리는 게 아니라, <strong>그 규율을 더 적은 시스템 경계에서 구현하려는 흐름</strong>입니다. 그래서 <a href="/learning/deep-dive/deep-dive-queue-visibility-timeout-acknack-playbook/">Queue Visibility Timeout·Ack/Nack·DLQ 플레이북</a>과 <a href="/learning/deep-dive/deep-dive-idempotency/">멱등성 설계</a>, <a href="/learning/deep-dive/deep-dive-transactional-inbox-idempotent-consumer-playbook/">Transactional Inbox</a>를 같이 보는 편이 맞습니다.</p>
<h3 id="4-sqlite와-postgres는-같은-범주처럼-보여도-쓰임새가-다르다">4) SQLite와 Postgres는 같은 범주처럼 보여도 쓰임새가 다르다</h3>
<p>SQLite가 빛나는 구간은 <strong>단일 노드, 배포 쉬움, 낮은 운영 오버헤드, 강한 로컬 내구성</strong>입니다. 반면 Postgres는 <strong>여러 워커, SQL 기반 운영 도구, 트랜잭션 일관성, 기존 운영 자산 재사용</strong>에 강합니다.</p>
<p>대략 이렇게 나누면 편합니다.</p>
<ul>
<li><strong>SQLite 적합</strong>: 에지/단일 인스턴스 앱, 로컬 자동화, 소규모 SaaS의 부가 작업, 배포형 제품</li>
<li><strong>Postgres 적합</strong>: 이미 RDS/Cloud SQL/managed PG를 쓰고 있고, 백오피스/웹훅/배치/내부 workflow를 같은 운영팀이 관리하는 경우</li>
<li><strong>전용 브로커 적합</strong>: subscriber 다수, 장기 backlog, 멀티리전 전달, 높은 fan-out, 독립 스케일이 핵심인 경우</li>
</ul>
<p>결국 요즘 팀들이 배우는 건 &ldquo;SQLite냐 Kafka냐&quot;가 아니라, <strong>작업군마다 적정 무게가 다르다</strong>는 사실입니다.</p>
<h3 id="5-앞으로의-차이는-기능-수보다-설명-가능성에서-난다">5) 앞으로의 차이는 기능 수보다 설명 가능성에서 난다</h3>
<p>브로커를 붙이면 확장성은 얻기 쉽지만, 작은 팀은 종종 &ldquo;이 작업이 왜 지금 이 상태인지&rdquo; 설명하는 데 더 많은 시간을 씁니다. 반대로 DB queue는 상태를 한눈에 보기 쉬워서 운영 설명 가능성이 좋아집니다.</p>
<p>그래서 최근 도입팀은 아래 KPI를 먼저 봅니다.</p>
<ul>
<li><code>oldest_runnable_age_seconds</code>: <strong>60초 이하</strong> 유지 목표, 중요 작업은 더 짧게</li>
<li><code>lease_expired_reclaim_rate</code>: <strong>1% 이하</strong> 목표</li>
<li><code>retry_inflation_ratio</code>: 재시도로 인한 총 실행 증가율 <strong>1.2 이하</strong> 권장</li>
<li><code>stuck_jobs_total</code>: 0이 이상적, 조금이라도 생기면 원인 추적</li>
<li><code>operator_replay_count</code>: 수동 재처리가 반복되면 구조 문제 신호</li>
</ul>
<p>핵심 우선순위는 보통 <strong>작업 유실 방지 &gt; 중복 효과 방지 &gt; 운영 설명 가능성 &gt; 처리량 최적화</strong> 순입니다. 작은 팀일수록 이 순서가 잘 맞습니다.</p>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-어떤-작업부터-옮길-것인가">1) 어떤 작업부터 옮길 것인가</h3>
<p>처음부터 핵심 주문 이벤트를 옮기는 건 권하지 않습니다. 보통은 아래 순서가 안전합니다.</p>
<ol>
<li>관리자성 백그라운드 작업</li>
<li>정기 배치와 스케줄성 작업</li>
<li>웹훅/이메일/알림 같은 재시도형 작업</li>
<li>사람이 운영 화면에서 직접 재실행해도 되는 워크플로</li>
</ol>
<p>반대로 아래는 보수적으로 봐야 합니다.</p>
<ul>
<li>다수 소비자가 같은 이벤트를 각자 해석하는 fan-out 구조</li>
<li>초당 수천 건 이상 장기 backlog가 생기는 흐름</li>
<li>리전 간 전달 보장이 핵심인 작업</li>
<li>업무상 &ldquo;한 번 늦는 것&quot;보다 &ldquo;절대 막히면 안 되는 것&quot;이 더 중요한 경우</li>
</ul>
<h3 id="2-권장-시작-구조">2) 권장 시작 구조</h3>
<p>가벼운 시작은 아래 정도면 충분합니다.</p>
<ul>
<li><code>jobs</code> 테이블: 상태, next_run_at, lease_until, retry_count, payload_ref</li>
<li><code>job_attempts</code> 테이블: 실패 원인, 실행 시간, operator replay 여부</li>
<li>워커는 <code>next_run_at &lt;= now()</code> and <code>lease_until &lt; now()</code> 기준으로 획득</li>
<li>실패 시 지수 backoff, 횟수 초과 시 dead 상태 또는 별도 quarantine 테이블 이동</li>
</ul>
<p>그리고 <a href="/learning/deep-dive/deep-dive-transactional-outbox-cdc/">Transactional Outbox + CDC</a>처럼, 사용자 요청 안에서 바로 외부 전송하지 말고 <strong>업무 상태 변경과 job enqueue를 같은 커밋에 묶는 규율</strong>이 중요합니다.</p>
<h3 id="3-언제-브로커로-나가야-하는가">3) 언제 브로커로 나가야 하는가</h3>
<p>아래 신호가 보이면 DB queue만으로 버티려 하지 않는 편이 좋습니다.</p>
<ul>
<li>backlog가 자주 <strong>수백만 건 이상</strong> 누적</li>
<li>가장 큰 테넌트 1곳이 전체 워커 시간을 <strong>30% 이상</strong> 점유</li>
<li>작업군마다 서로 다른 소비자 그룹과 재처리 정책이 필요</li>
<li>DB lock, vacuum, replica lag가 queue workload 때문에 눈에 띄게 악화</li>
<li>운영자가 SQL 대신 별도 도구와 시각화를 더 필요로 하기 시작</li>
</ul>
<p>즉 DB queue는 &ldquo;영원한 기본값&quot;이 아니라, <strong>명확한 범위에서 매우 강한 기본값</strong>에 가깝습니다.</p>
<h3 id="4-4주-도입-플랜">4) 4주 도입 플랜</h3>
<p><strong>1주차</strong><br>
현재 비동기 작업을 <code>운영성 작업</code>, <code>핵심 도메인 이벤트</code>, <code>장기 backlog형</code>으로 분류합니다.</p>
<p><strong>2주차</strong><br>
가장 단순한 작업군 1개를 골라 queue depth, oldest runnable age, retry inflation 대시보드를 붙입니다.</p>
<p><strong>3주차</strong><br>
lease timeout, idempotency, dead job 격리, operator replay 기록을 추가합니다.</p>
<p><strong>4주차</strong><br>
기존 외부 브로커 작업과 비용, 장애 대응 시간, 수동 복구 시간을 비교해 계속 확대할지 판단합니다.</p>
<h2 id="빠른-선택-매트릭스">빠른 선택 매트릭스</h2>
<p>팀이 실제로 헷갈리는 지점은 &ldquo;지금 바로 DB queue로 가도 되나&quot;보다 <strong>어떤 작업은 남기고 어떤 작업만 옮겨야 하나</strong>입니다. 그래서 아래처럼 작업군별로 의사결정을 나누면 시행착오가 크게 줄어듭니다.</p>
<table>
  <thead>
      <tr>
          <th>작업 유형</th>
          <th>SQLite</th>
          <th>Postgres</th>
          <th>전용 브로커/워크플로 엔진</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>관리자성 재처리, 내부 배치, 소규모 cron</td>
          <td>매우 적합</td>
          <td>매우 적합</td>
          <td>과할 가능성 큼</td>
      </tr>
      <tr>
          <td>웹훅 전달, 이메일, 썸네일 생성</td>
          <td>제한적 적합</td>
          <td>적합</td>
          <td>fan-out이 크면 적합</td>
      </tr>
      <tr>
          <td>주문/결제 후속처리처럼 유실이 매우 민감한 작업</td>
          <td>보수적</td>
          <td>조건부 적합</td>
          <td>자주 적합</td>
      </tr>
      <tr>
          <td>다수 구독자가 같은 이벤트를 소비하는 구조</td>
          <td>부적합</td>
          <td>제한적</td>
          <td>매우 적합</td>
      </tr>
      <tr>
          <td>멀티리전, 장기 backlog, 독립 확장이 핵심</td>
          <td>부적합</td>
          <td>보수적</td>
          <td>매우 적합</td>
      </tr>
  </tbody>
</table>
<p>판단 기준은 화려한 기능 수가 아닙니다. 아래 네 질문에 두 개 이상 &ldquo;예&quot;가 나오면 전용 계층을 먼저 보는 편이 안전합니다.</p>
<ol>
<li>같은 이벤트를 여러 소비자 그룹이 서로 다른 속도로 읽어야 하는가?</li>
<li>backlog가 길게 쌓여도 온라인 트랜잭션과 분리된 확장이 필요한가?</li>
<li>테넌트 간 noisy neighbor를 강하게 격리해야 하는가?</li>
<li>운영팀이 SQL보다 별도 관측 도구와 리플레이 도구에 더 의존하게 될 가능성이 큰가?</li>
</ol>
<p>반대로 아래 조건이면 DB queue 쪽이 실무적으로 더 이득일 때가 많습니다.</p>
<ul>
<li>enqueue와 비즈니스 상태 변경을 같은 트랜잭션으로 묶고 싶다.</li>
<li>운영자가 작업 상태를 SQL 한 번으로 설명하고 수습할 수 있어야 한다.</li>
<li>워커 수보다 운영 인력 부족이 더 큰 제약이다.</li>
<li>핵심 목표가 초고속 fan-out보다 예측 가능한 운영 복구다.</li>
</ul>
<p>이 매트릭스는 <a href="/learning/deep-dive/deep-dive-transactional-outbox-cdc/">Transactional Outbox + CDC</a>, <a href="/learning/deep-dive/deep-dive-lag-aware-read-routing-follower-reads-playbook/">Lag Aware Read Routing</a>, <a href="/learning/deep-dive/deep-dive-outlier-detection-ejection-playbook/">Outlier Detection/Ejection</a>처럼 이미 운영에 쓰는 규율과 같이 봐야 제대로 작동합니다.</p>
<h2 id="도입-전에-꼭-문서화할-운영-계약">도입 전에 꼭 문서화할 운영 계약</h2>
<p>DB queue는 코드보다 운영 계약이 먼저입니다. 아래 항목이 비어 있으면 구현이 간단해 보여도 실제 운영은 빠르게 흐려집니다.</p>
<h3 id="1-lease와-재시도-계약">1) lease와 재시도 계약</h3>
<ul>
<li>한 작업을 몇 초까지 점유할 수 있는가</li>
<li>lease 만료 후 reclaim은 몇 번까지 허용할 것인가</li>
<li>재시도 간격은 고정인지, 지수 backoff인지</li>
<li>최대 재시도 초과 시 dead 상태로 둘지, quarantine 테이블로 보낼지</li>
</ul>
<p>이 계약이 없으면 중복 실행과 stuck job이 섞이면서 &ldquo;성공했는데 또 돌았다&quot;와 &ldquo;실패했는데 영원히 안 돌아온다&quot;가 동시에 생깁니다.</p>
<h3 id="2-운영자-개입-계약">2) 운영자 개입 계약</h3>
<ul>
<li>운영자가 재실행할 때 payload를 수정할 수 있는가</li>
<li>replay reason을 반드시 남기는가</li>
<li>수동 재실행도 같은 idempotency 규칙을 타는가</li>
<li>실패 원인 분류를 애플리케이션/외부 API/데이터 문제로 나눠 저장하는가</li>
</ul>
<p>특히 운영자가 개입하는 시스템은 <a href="/posts/2026-04-14-execution-receipt-agent-operations-trend/">Execution Receipt</a>처럼 누가, 왜, 어떤 근거로 재실행했는지 남겨야 나중에 설명이 됩니다.</p>
<h3 id="3-승격-경계-계약">3) 승격 경계 계약</h3>
<ul>
<li>queue depth가 얼마를 넘으면 브로커 분리를 검토할 것인가</li>
<li>특정 테넌트 점유율이 몇 퍼센트를 넘으면 격리 설계를 시작할 것인가</li>
<li>replica lag나 vacuum 부하가 어느 수준이면 queue 전용 저장소를 분리할 것인가</li>
</ul>
<p>좋은 팀은 처음부터 완벽한 확장 구조를 만들기보다, <strong>언제 현재 구조를 포기해야 하는지</strong>를 먼저 적어 둡니다. 이게 있어야 단순화가 기술 부채가 아니라 의도된 단계 전략이 됩니다.</p>
<h2 id="현업에서-자주-터지는-안티패턴">현업에서 자주 터지는 안티패턴</h2>
<h3 id="테이블-하나면-끝난다-착각">&ldquo;테이블 하나면 끝난다&rdquo; 착각</h3>
<p>jobs 테이블만 만들고 attempt 이력, DLQ성 격리, replay reason을 빼면 초반엔 빨라 보이지만 장애 한 번에 운영비가 급등합니다. 최소한 <code>jobs</code>, <code>job_attempts</code>, dead/quarantine 경로는 분리하는 편이 낫습니다.</p>
<h3 id="oltp와-장기-배치를-무방비로-섞는-설계">OLTP와 장기 배치를 무방비로 섞는 설계</h3>
<p>같은 Postgres를 써도 모두 같은 우선순위로 처리하면 안 됩니다. 대형 backfill, 장기 reconciliation, 느린 외부 API retry를 낮은 우선순위 큐로 격리하지 않으면 온라인 트래픽과 잠깐씩 충돌하다가 결국 &ldquo;왜 낮에는 괜찮다가 야간 배치만 돌면 느려지지?&ldquo;가 반복됩니다.</p>
<h3 id="성공-기준을-처리량-하나로만-보는-운영">성공 기준을 처리량 하나로만 보는 운영</h3>
<p>DB queue의 강점은 TPS 1등이 아니라 복구 설명 가능성입니다. 따라서 성공 기준도 <code>평균 처리량</code> 하나가 아니라 <code>oldest runnable age</code>, <code>retry inflation</code>, <code>operator replay count</code>, <code>stuck jobs</code>를 같이 봐야 합니다. 처리량만 맞추면 나중에 운영자가 감당할 빚이 숨어 버립니다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<ol>
<li>
<p><strong>단순화는 공짜가 아니다</strong><br>
DB queue로 모으면 시스템 수는 줄지만, DB 자체가 더 중요한 공용 자원이 됩니다. 경계를 잘못 잡으면 병목이 한곳에 몰립니다.</p>
</li>
<li>
<p><strong>fan-out과 다중 소비자 요구를 얕보면 안 된다</strong><br>
한 작업을 여러 팀, 여러 서비스가 각기 다르게 소비해야 한다면 전용 브로커가 더 자연스럽습니다.</p>
</li>
<li>
<p><strong>운영 가시성이 좋아 보여도 격리 문제는 남는다</strong><br>
같은 Postgres라도 OLTP와 장기 배치를 무심코 섞으면 replica lag, vacuum, lock 경합이 커질 수 있습니다.</p>
</li>
<li>
<p><strong>SQLite는 특히 범위를 명확히 해야 한다</strong><br>
로컬 내구성과 단순성은 훌륭하지만, 다중 노드 확장과 강한 분산 조정까지 기대하면 금방 무리가 옵니다.</p>
</li>
<li>
<p><strong>브로커를 안 쓴다고 사고가 줄어드는 것은 아니다</strong><br>
중복 방지, 재처리, poison job, 수동 복구 절차는 어떤 형태로든 필요합니다. 규율을 생략하면 단순화가 아니라 무방비가 됩니다.</p>
</li>
</ol>
<h2 id="체크리스트-또는-연습">체크리스트 또는 연습</h2>
<h3 id="체크리스트">체크리스트</h3>
<ul>
<li><input disabled="" type="checkbox"> 현재 비동기 작업을 fan-out형과 단일 소유자형으로 나눴다.</li>
<li><input disabled="" type="checkbox"> queue depth, oldest runnable age, retry inflation을 측정할 수 있다.</li>
<li><input disabled="" type="checkbox"> lease timeout과 idempotency key 규칙이 있다.</li>
<li><input disabled="" type="checkbox"> operator replay 이유와 실행 이력이 남는다.</li>
<li><input disabled="" type="checkbox"> backlog가 커질 때 브로커로 분리할 경계 조건을 문서화했다.</li>
</ul>
<h3 id="연습-과제">연습 과제</h3>
<ol>
<li>현재 팀의 비동기 작업 10개를 적고, 각각을 <code>DB queue 가능</code>, <code>브로커 유지</code>, <code>사람 승인 필요</code>로 나눠 보세요.</li>
<li>가장 단순한 백그라운드 작업 하나를 골라, queue depth와 oldest runnable age 목표치를 직접 숫자로 적어 보세요.</li>
<li>지난달 수동 재처리한 작업이 있다면, 그 이유가 데이터 유실인지, 중복 방지 부족인지, 운영 도구 부족인지 분류해 보세요.</li>
</ol>
<h2 id="관련-글">관련 글</h2>
<ul>
<li><a href="/learning/deep-dive/deep-dive-queue-visibility-timeout-acknack-playbook/">Queue Visibility Timeout·Ack/Nack·DLQ 재처리 설계 플레이북</a></li>
<li><a href="/learning/deep-dive/deep-dive-transactional-outbox-cdc/">트랜잭션 아웃박스 + CDC</a></li>
<li><a href="/learning/deep-dive/deep-dive-distributed-scheduler-singleton-playbook/">분산 스케줄러 Singleton 실행 보장 플레이북</a></li>
<li><a href="/learning/deep-dive/deep-dive-reconciliation-ledger-pipeline/">Reconciliation 파이프라인으로 금액·포인트 데이터 불일치 줄이기</a></li>
<li><a href="/posts/2026-04-18-dev-news-senior-insights/">2026-04-18 개발 뉴스 시니어 인사이트</a></li>
</ul>
]]></content:encoded></item></channel></rss>