<?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>Event-Delivery on Tarragon</title><link>https://tarrragon.github.io/blog/tags/event-delivery/</link><description>Recent content in Event-Delivery on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 22 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/event-delivery/index.xml" rel="self" type="application/rss+xml"/><item><title>模組三：訊息佇列與事件傳遞</title><link>https://tarrragon.github.io/blog/backend/03-message-queue/</link><pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/03-message-queue/</guid><description>&lt;p>訊息佇列模組的核心目標是說明事件離開單一 process 後，如何處理持久化、重試、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/duplicate-delivery/" data-link-title="Duplicate Delivery" data-link-desc="說明同一個訊息被處理多次時如何保持結果穩定">重複投遞&lt;/a>與 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/consumer/" data-link-title="Consumer" data-link-desc="說明 consumer 如何取得等待處理的工作並產生業務結果">consumer&lt;/a> 協調。語言教材會先處理本地 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/queue/" data-link-title="Queue" data-link-desc="說明 queue 如何保存等待處理的工作並形成容量邊界">queue&lt;/a> abstraction、publisher port、processor 與 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency&lt;/a> interface；本模組負責 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker&lt;/a> 的具體語意。&lt;/p>
&lt;h2 id="vendor--platform-清單">Vendor / Platform 清單&lt;/h2>
&lt;p>實作時的常用選擇見 &lt;a href="https://tarrragon.github.io/blog/backend/03-message-queue/vendors/" data-link-title="訊息佇列 Vendor 清單" data-link-desc="規劃 broker、event streaming 與 managed queue 的服務頁撰寫順序與判準">vendors&lt;/a> — T1 收錄 RabbitMQ / Kafka / NATS / Redis Streams / AWS SQS / Google Pub/Sub，每個 vendor 有定位、適用場景、取捨與預計實作話題的骨架。&lt;/p>
&lt;p>Deep article（vendor 自身的配置、故障、容量）跟 migration playbook（跨 vendor 遷移流程）的撰寫進度見 &lt;a href="https://tarrragon.github.io/blog/backend/03-message-queue/vendors/" data-link-title="訊息佇列 Vendor 清單" data-link-desc="規劃 broker、event streaming 與 managed queue 的服務頁撰寫順序與判準">vendors/&lt;/a> 的「內容覆蓋進度」段。&lt;/p>
&lt;h2 id="暫定分類">暫定分類&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>分類&lt;/th>
 &lt;th>內容方向&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>RabbitMQ&lt;/td>
 &lt;td>exchange、queue、routing key、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/ack-nack/" data-link-title="Ack / Nack" data-link-desc="說明 consumer 如何向 broker 回報訊息處理結果">ack/nack&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/dead-letter-queue/" data-link-title="Dead-Letter Queue" data-link-desc="說明 dead-letter queue 如何隔離多次處理失敗的訊息">dead-letter queue&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>NATS&lt;/td>
 &lt;td>subject、consumer、JetStream、at-least-once delivery&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Kafka&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/topic/" data-link-title="Topic" data-link-desc="說明 topic 如何把事件依主題分流給不同訂閱者">topic&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/partition/" data-link-title="Partition" data-link-desc="說明事件流如何切分成多個可並行處理的有序片段">partition&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/consumer-group/" data-link-title="Consumer Group" data-link-desc="說明一組 consumer 如何共同分攤 stream 或 topic 的處理責任">consumer group&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/offset/" data-link-title="Offset" data-link-desc="說明 consumer 在事件流中的讀取位置與重放基準">offset&lt;/a>、ordering&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Redis Streams&lt;/td>
 &lt;td>stream、consumer group、pending entry、claim&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Outbox&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/transaction/" data-link-title="Transaction" data-link-desc="說明 transaction 如何讓一組資料變更一起成功或一起回復">transaction&lt;/a> outbox、poller、publisher、重試策略&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Idempotency&lt;/td>
 &lt;td>idempotency key、dedup store、replay safety&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="選型入口">選型入口&lt;/h2>
&lt;p>訊息佇列選型的核心判斷是工作離開 request 或 process 後需要什麼投遞保證。當工作需要排隊、重試、跨服務傳遞、多 consumer 協作或事件補送時，&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker&lt;/a> 與 outbox 值得優先評估。&lt;/p>
&lt;p>RabbitMQ 適合明確 routing、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/ack-nack/" data-link-title="Ack / Nack" data-link-desc="說明 consumer 如何向 broker 回報訊息處理結果">ack/nack&lt;/a> 與工作佇列；NATS 適合 subject-based messaging 與較輕量的服務通訊，搭配 JetStream 可加入持久化；Kafka 適合高吞吐事件流、partition 與長期 replay；Redis Streams 適合 Redis 生態內的 stream 與 consumer group；&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/outbox-pattern/" data-link-title="Outbox Pattern" data-link-desc="說明資料庫狀態變更與事件發布如何透過 outbox 維持一致">outbox&lt;/a> 解決資料寫入與事件發布的一致性；&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency&lt;/a> 解決重複投遞造成的結果穩定性；&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/retry-budget/" data-link-title="Retry Budget" data-link-desc="說明重試次數如何受整體容量與錯誤預算限制">retry budget&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/jitter/" data-link-title="Jitter" data-link-desc="說明重試或排程加入隨機偏移如何降低同步尖峰">jitter&lt;/a> 則控制故障期間的重試壓力。&lt;/p></description><content:encoded><![CDATA[<p>訊息佇列模組的核心目標是說明事件離開單一 process 後，如何處理持久化、重試、<a href="/blog/backend/knowledge-cards/duplicate-delivery/" data-link-title="Duplicate Delivery" data-link-desc="說明同一個訊息被處理多次時如何保持結果穩定">重複投遞</a>與 <a href="/blog/backend/knowledge-cards/consumer/" data-link-title="Consumer" data-link-desc="說明 consumer 如何取得等待處理的工作並產生業務結果">consumer</a> 協調。語言教材會先處理本地 <a href="/blog/backend/knowledge-cards/queue/" data-link-title="Queue" data-link-desc="說明 queue 如何保存等待處理的工作並形成容量邊界">queue</a> abstraction、publisher port、processor 與 <a href="/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency</a> interface；本模組負責 <a href="/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker</a> 的具體語意。</p>
<h2 id="vendor--platform-清單">Vendor / Platform 清單</h2>
<p>實作時的常用選擇見 <a href="/blog/backend/03-message-queue/vendors/" data-link-title="訊息佇列 Vendor 清單" data-link-desc="規劃 broker、event streaming 與 managed queue 的服務頁撰寫順序與判準">vendors</a> — T1 收錄 RabbitMQ / Kafka / NATS / Redis Streams / AWS SQS / Google Pub/Sub，每個 vendor 有定位、適用場景、取捨與預計實作話題的骨架。</p>
<p>Deep article（vendor 自身的配置、故障、容量）跟 migration playbook（跨 vendor 遷移流程）的撰寫進度見 <a href="/blog/backend/03-message-queue/vendors/" data-link-title="訊息佇列 Vendor 清單" data-link-desc="規劃 broker、event streaming 與 managed queue 的服務頁撰寫順序與判準">vendors/</a> 的「內容覆蓋進度」段。</p>
<h2 id="暫定分類">暫定分類</h2>
<table>
  <thead>
      <tr>
          <th>分類</th>
          <th>內容方向</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>RabbitMQ</td>
          <td>exchange、queue、routing key、<a href="/blog/backend/knowledge-cards/ack-nack/" data-link-title="Ack / Nack" data-link-desc="說明 consumer 如何向 broker 回報訊息處理結果">ack/nack</a>、<a href="/blog/backend/knowledge-cards/dead-letter-queue/" data-link-title="Dead-Letter Queue" data-link-desc="說明 dead-letter queue 如何隔離多次處理失敗的訊息">dead-letter queue</a></td>
      </tr>
      <tr>
          <td>NATS</td>
          <td>subject、consumer、JetStream、at-least-once delivery</td>
      </tr>
      <tr>
          <td>Kafka</td>
          <td><a href="/blog/backend/knowledge-cards/topic/" data-link-title="Topic" data-link-desc="說明 topic 如何把事件依主題分流給不同訂閱者">topic</a>、<a href="/blog/backend/knowledge-cards/partition/" data-link-title="Partition" data-link-desc="說明事件流如何切分成多個可並行處理的有序片段">partition</a>、<a href="/blog/backend/knowledge-cards/consumer-group/" data-link-title="Consumer Group" data-link-desc="說明一組 consumer 如何共同分攤 stream 或 topic 的處理責任">consumer group</a>、<a href="/blog/backend/knowledge-cards/offset/" data-link-title="Offset" data-link-desc="說明 consumer 在事件流中的讀取位置與重放基準">offset</a>、ordering</td>
      </tr>
      <tr>
          <td>Redis Streams</td>
          <td>stream、consumer group、pending entry、claim</td>
      </tr>
      <tr>
          <td>Outbox</td>
          <td><a href="/blog/backend/knowledge-cards/transaction/" data-link-title="Transaction" data-link-desc="說明 transaction 如何讓一組資料變更一起成功或一起回復">transaction</a> outbox、poller、publisher、重試策略</td>
      </tr>
      <tr>
          <td>Idempotency</td>
          <td>idempotency key、dedup store、replay safety</td>
      </tr>
  </tbody>
</table>
<h2 id="選型入口">選型入口</h2>
<p>訊息佇列選型的核心判斷是工作離開 request 或 process 後需要什麼投遞保證。當工作需要排隊、重試、跨服務傳遞、多 consumer 協作或事件補送時，<a href="/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker</a> 與 outbox 值得優先評估。</p>
<p>RabbitMQ 適合明確 routing、<a href="/blog/backend/knowledge-cards/ack-nack/" data-link-title="Ack / Nack" data-link-desc="說明 consumer 如何向 broker 回報訊息處理結果">ack/nack</a> 與工作佇列；NATS 適合 subject-based messaging 與較輕量的服務通訊，搭配 JetStream 可加入持久化；Kafka 適合高吞吐事件流、partition 與長期 replay；Redis Streams 適合 Redis 生態內的 stream 與 consumer group；<a href="/blog/backend/knowledge-cards/outbox-pattern/" data-link-title="Outbox Pattern" data-link-desc="說明資料庫狀態變更與事件發布如何透過 outbox 維持一致">outbox</a> 解決資料寫入與事件發布的一致性；<a href="/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency</a> 解決重複投遞造成的結果穩定性；<a href="/blog/backend/knowledge-cards/retry-budget/" data-link-title="Retry Budget" data-link-desc="說明重試次數如何受整體容量與錯誤預算限制">retry budget</a> 與 <a href="/blog/backend/knowledge-cards/jitter/" data-link-title="Jitter" data-link-desc="說明重試或排程加入隨機偏移如何降低同步尖峰">jitter</a> 則控制故障期間的重試壓力。</p>
<p>接近真實網路服務的例子包括付款後寄信、影片轉檔、訂單事件傳給多個系統、IoT readings pipeline 與跨節點通知。這些場景的共同問題是 <a href="/blog/backend/knowledge-cards/delivery-semantics/" data-link-title="Delivery Semantics" data-link-desc="說明事件投遞語意如何定義遺失、重複、順序與補償策略">delivery semantics</a>，因此本模組會先處理 broker 模型、retry、<a href="/blog/backend/knowledge-cards/dead-letter-queue/" data-link-title="Dead-Letter Queue" data-link-desc="說明 dead-letter queue 如何隔離多次處理失敗的訊息">DLQ</a>、outbox 與 consumer 設計。</p>
<h2 id="與語言教材的分工">與語言教材的分工</h2>
<p>語言教材處理本地 <a href="/blog/backend/knowledge-cards/backpressure/" data-link-title="Backpressure" data-link-desc="說明下游處理速度不足時系統如何讓上游依下游能力送出工作">backpressure</a>、processor 邊界、port / <a href="/blog/backend/knowledge-cards/message-protocol/" data-link-title="Message Protocol" data-link-desc="說明 queue 或 stream message 如何對齊格式與處理語意">Message Protocol</a> 設計與單一 process 內的去重。Backend message queue 模組處理 broker selection、ack/nack、DLQ、consumer group、outbox 與跨 process 重試。</p>
<h2 id="案例驅動讀法">案例驅動讀法</h2>
<p>佇列案例的核心讀法是先辨識遷移的是「資料路徑」還是「治理路徑」，再決定先做 broker 切換還是治理收斂。</p>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>先看章節</th>
          <th>回寫目標</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/03-message-queue/cases/meta-foqs-global-migration/" data-link-title="3.C1 Meta：FOQS 從區域到全域佇列遷移" data-link-desc="佇列架構如何在不中斷下升級成 disaster-ready 模式。">3.C1 Meta：FOQS 全域遷移</a></td>
          <td><a href="/blog/backend/03-message-queue/broker-basics/" data-link-title="3.1 broker 基礎與投遞模型" data-link-desc="先理解 broker、queue、consumer 與 delivery semantics">3.1</a>、<a href="/blog/backend/03-message-queue/durable-queue/" data-link-title="3.2 durable queue 與重試策略" data-link-desc="整理持久化佇列、DLQ 與重試流程">3.2</a></td>
          <td>把跨區 queue 路由與可用性邊界前置</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/cases/vmware-kafka-to-msk/" data-link-title="3.C2 VMware Tanzu CloudHealth：Kafka 轉 Amazon MSK" data-link-desc="自管 Kafka 遷移到託管平台時的治理重點。">3.C2 VMware：Kafka -&gt; MSK</a></td>
          <td><a href="/blog/backend/03-message-queue/broker-basics/" data-link-title="3.1 broker 基礎與投遞模型" data-link-desc="先理解 broker、queue、consumer 與 delivery semantics">3.1</a>、<a href="/blog/backend/03-message-queue/consumer-design/" data-link-title="3.4 consumer 設計與去重" data-link-desc="整理 consumer、checkpoint 與 replay safety">3.4</a></td>
          <td>把 managed broker 遷移轉成 ACL/lag/回退治理</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/cases/linkedin-topicgc-kafka-governance/" data-link-title="3.C3 LinkedIn：TopicGC 與 Kafka 治理轉換" data-link-desc="Kafka topic 從手動治理轉自動治理對叢集的影響。">3.C3 LinkedIn：TopicGC</a></td>
          <td><a href="/blog/backend/03-message-queue/consumer-design/" data-link-title="3.4 consumer 設計與去重" data-link-desc="整理 consumer、checkpoint 與 replay safety">3.4</a></td>
          <td>把 topic 生命週期治理納入可靠性成本模型</td>
      </tr>
  </tbody>
</table>
<h2 id="跨語言適配評估">跨語言適配評估</h2>
<p>訊息佇列使用方式會受語言的 worker model、錯誤處理、序列化、背景任務框架與 idempotency 設計影響。同步 runtime 要控制 consumer thread 數量與 ack <a href="/blog/backend/knowledge-cards/timeout/" data-link-title="Timeout" data-link-desc="說明等待外部操作的時間上限如何保護資源與使用者體驗">timeout</a>；async runtime 要處理 backpressure 與 long-running handler；輕量並發 runtime 要限制同時處理量，避免 consumer 擴張超過下游容量。強型別語言適合建立 event schema 與 command model；動態語言要補足 payload validation、dead-letter 診斷與重播測試。</p>
<h2 id="章節列表">章節列表</h2>
<table>
  <thead>
      <tr>
          <th>章節</th>
          <th>主題</th>
          <th>關鍵收穫</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/03-message-queue/broker-basics/" data-link-title="3.1 broker 基礎與投遞模型" data-link-desc="先理解 broker、queue、consumer 與 delivery semantics">3.1</a></td>
          <td>broker 基礎與投遞模型</td>
          <td>看懂 exchange、topic、consumer 與 delivery semantics</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/durable-queue/" data-link-title="3.2 durable queue 與重試策略" data-link-desc="整理持久化佇列、DLQ 與重試流程">3.2</a></td>
          <td><a href="/blog/backend/knowledge-cards/durable-queue/" data-link-title="Durable Queue" data-link-desc="說明可持久化的 queue 如何在重啟與失敗後保留待處理工作">durable queue</a> 與重試策略</td>
          <td>規劃持久化、ack/nack、DLQ 與 retry</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/outbox-pattern/" data-link-title="3.3 outbox pattern 與發佈一致性" data-link-desc="把 transaction 與 event publish 分離">3.3</a></td>
          <td><a href="/blog/backend/knowledge-cards/outbox-pattern/" data-link-title="Outbox Pattern" data-link-desc="說明資料庫狀態變更與事件發布如何透過 outbox 維持一致">outbox pattern</a> 與發佈一致性</td>
          <td>把交易寫入與事件發佈分離</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/consumer-design/" data-link-title="3.4 consumer 設計與去重" data-link-desc="整理 consumer、checkpoint 與 replay safety">3.4</a></td>
          <td>consumer 設計與去重</td>
          <td>設計 idempotency、<a href="/blog/backend/knowledge-cards/checkpoint/" data-link-title="Checkpoint" data-link-desc="說明長時間處理流程如何記錄可恢復進度">checkpoint</a> 與 replay safety</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/red-team-delivery-layer/" data-link-title="3.5 攻擊者視角（紅隊）：傳遞層弱點判讀" data-link-desc="從重複投遞、重放濫用、毒訊息與容量壓力，盤點 message delivery 的主要弱點">3.5</a></td>
          <td>攻擊者視角（紅隊）：傳遞層弱點判讀</td>
          <td>用重放、重複、毒訊息與延遲累積檢查非同步傳遞邊界</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/processing-recovery-semantics/" data-link-title="3.6 Processing Semantics 與 Recovery Semantics" data-link-desc="說明投遞成功、處理成功與恢復成功為何是三個不同判斷。">3.6</a></td>
          <td>Processing Semantics 與 Recovery Semantics</td>
          <td>分辨投遞成功、處理成功與恢復成功</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/event-contract-replay-boundary/" data-link-title="3.7 Event Contract 與 Replay Boundary" data-link-desc="說明 event schema、idempotency key、replay window 與補償如何先於 broker 選型。">3.7</a></td>
          <td>Event Contract 與 Replay Boundary</td>
          <td>定義 event schema、idempotency key、replay window 與補償邊界</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/queue-consumer-retry-replay-handoff/" data-link-title="3.8 Queue Consumer Retry 與 Replay Handoff（實作示範）" data-link-desc="以 order_created consumer 示範 queue 路徑如何交付 idempotency evidence、DLQ handling、replay runbook 與 incident decision log。">3.8</a></td>
          <td>Queue Consumer Retry 與 Replay Handoff 實作示範</td>
          <td>以訂單事件 consumer 示範 evidence、DLQ、replay runbook 與 decision log</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/03-message-queue/cases/" data-link-title="模組三案例正文" data-link-desc="訊息佇列與事件傳遞的轉換案例入口、含通用案例與 6 個 vendor 的真實 production case 庫。">3.C</a></td>
          <td>轉換案例正文</td>
          <td>把 queue 架構、broker 遷移與 topic 治理轉成可操作案例</td>
      </tr>
  </tbody>
</table>
<p>反例與規模對照入口： <a href="/blog/backend/03-message-queue/cases/failure-queue-semantics-mismatch-cutover/" data-link-title="3.C9 反例：Queue 語義切換誤配" data-link-desc="at-least-once / exactly-once 語義誤配導致資料重複與遺漏。">3.C9 反例</a> / <a href="/blog/backend/03-message-queue/cases/contrast-queue-model-by-scale/" data-link-title="3.C10 對照：規模差異下的佇列模型" data-link-desc="同一 queue 模型在不同規模下的治理與失敗邊界差異。">3.C10 對照</a>。</p>
<p>回退判讀寫法見 <a href="/blog/backend/00-service-selection/cases/post-scale-migration-language-tool-architecture/#%e5%9b%9e%e9%80%80%e5%88%a4%e8%ae%80%e5%af%ab%e6%b3%95" data-link-title="營運後技術轉換：語言、工具與架構何時該換" data-link-desc="服務營運一段時間後，如何判讀何時該轉語言、工具或架構，並用案例說明轉換動機。">0.C4 回退判讀寫法</a>，queue 案例要優先保留 delivery semantics、lag、DLQ 與 replay 條件。</p>
<p>跨模組端到端串聯（DB → cache → event → observability）見 <a href="/blog/backend/00-service-selection/cross-module-checkout-episode/" data-link-title="0.15 跨模組 Checkout Episode：從資料寫入到觀測證據" data-link-desc="以 checkout 為切片，走完 DB write → cache invalidation → event publish → observability evidence 四層串聯，標示各模組的交接欄位與失敗判讀">0.15 跨模組 Checkout Episode</a>。</p>
<h2 id="觀念網路補完方向">觀念網路補完方向</h2>
<p>訊息佇列章節下一輪的核心責任是把「投遞成功」和「業務結果正確」分開。現有章節已經有 broker、durable queue、outbox 與 consumer design，但還需要補上 delivery semantics、processing semantics 與 recovery semantics 的三層關係，讓讀者知道 queue 失敗同時包括訊息遺失、重複副作用、順序錯亂、重播風險與下游壓力放大。</p>
<table>
  <thead>
      <tr>
          <th>補完方向</th>
          <th>需要回答的問題</th>
          <th>主要路由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Delivery semantics</td>
          <td>broker 如何 ack、nack、redelivery、retry、送入 DLQ</td>
          <td><a href="/blog/backend/knowledge-cards/delivery-semantics/" data-link-title="Delivery Semantics" data-link-desc="說明事件投遞語意如何定義遺失、重複、順序與補償策略">delivery semantics</a>、<a href="/blog/backend/03-message-queue/durable-queue/" data-link-title="3.2 durable queue 與重試策略" data-link-desc="整理持久化佇列、DLQ 與重試流程">3.2</a></td>
      </tr>
      <tr>
          <td>Processing semantics</td>
          <td>consumer 的副作用是否能承受重複、亂序與部分失敗</td>
          <td><a href="/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency</a>、<a href="/blog/backend/06-reliability/idempotency-replay/" data-link-title="6.12 Idempotency 與 Replay 驗證" data-link-desc="把重試、重播與冪等性從口頭約定變成可驗證屬性">6.12</a></td>
      </tr>
      <tr>
          <td>Recovery semantics</td>
          <td>replay、checkpoint、offset 與補償是否可重播與驗證</td>
          <td><a href="/blog/backend/knowledge-cards/offset/" data-link-title="Offset" data-link-desc="說明 consumer 在事件流中的讀取位置與重放基準">offset</a>、<a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19</a></td>
      </tr>
      <tr>
          <td>Outbox boundary</td>
          <td>資料庫交易與事件發布是否有一致性邊界</td>
          <td><a href="/blog/backend/knowledge-cards/outbox-pattern/" data-link-title="Outbox Pattern" data-link-desc="說明資料庫狀態變更與事件發布如何透過 outbox 維持一致">outbox pattern</a>、<a href="/blog/backend/01-database/transaction-boundary/" data-link-title="1.3 Transaction 與一致性邊界" data-link-desc="交易邊界、isolation level、retry 策略、distributed transaction（2PC、Saga）與跨 region 強一致取捨">1.3</a></td>
      </tr>
      <tr>
          <td>Poison handling</td>
          <td>壞訊息是否會卡住 consumer 或被無限重試</td>
          <td><a href="/blog/backend/knowledge-cards/poison-message/" data-link-title="Poison Message" data-link-desc="說明特定訊息內容如何穩定造成 consumer 失敗">poison message</a>、<a href="/blog/backend/knowledge-cards/dead-letter-queue/" data-link-title="Dead-Letter Queue" data-link-desc="說明 dead-letter queue 如何隔離多次處理失敗的訊息">dead-letter queue</a></td>
      </tr>
  </tbody>
</table>
<p>這些方向要用非同步服務自己的語意展開。寄信、開 invoice、更新 CRM、同步 search index、發 webhook 的副作用不同，retry、DLQ 與 replay 的判準也不同。</p>
<h2 id="知識卡補強方向">知識卡補強方向</h2>
<p>佇列模組的 knowledge card 缺口集中在「處理語意」與「恢復語意」。已有 <a href="/blog/backend/knowledge-cards/consumer-lag/" data-link-title="Consumer Lag" data-link-desc="說明 consumer lag 如何反映訊息堆積、處理能力與容量風險">consumer lag</a>、<a href="/blog/backend/knowledge-cards/retry-budget/" data-link-title="Retry Budget" data-link-desc="說明重試次數如何受整體容量與錯誤預算限制">retry budget</a>、<a href="/blog/backend/knowledge-cards/poison-message/" data-link-title="Poison Message" data-link-desc="說明特定訊息內容如何穩定造成 consumer 失敗">poison message</a> 與 <a href="/blog/backend/knowledge-cards/offset/" data-link-title="Offset" data-link-desc="說明 consumer 在事件流中的讀取位置與重放基準">offset</a> 可以作為第一批錨點。</p>
<p>第二批卡片已補上 <a href="/blog/backend/knowledge-cards/processing-semantics/" data-link-title="Processing Semantics" data-link-desc="說明 consumer 處理事件後業務結果是否正確，與投遞成功分屬不同責任">processing semantics</a>、<a href="/blog/backend/knowledge-cards/recovery-semantics/" data-link-title="Recovery Semantics" data-link-desc="說明事件處理失敗後能否透過 replay、checkpoint 與補償重建正確狀態並驗證">recovery semantics</a>、<a href="/blog/backend/knowledge-cards/replay-window/" data-link-title="Replay Window" data-link-desc="說明事件可重播的時間或 offset 範圍邊界，由 retention 與 checkpoint 決定">replay window</a>、<a href="/blog/backend/knowledge-cards/consumer-pause/" data-link-title="Consumer Pause" data-link-desc="說明暫停消費作為事故控制手段，止住錯誤副作用擴大">consumer pause</a>、<a href="/blog/backend/knowledge-cards/event-schema-compatibility/" data-link-title="Event Schema Compatibility" data-link-desc="說明 event schema 演進時，新舊 producer 與 consumer 能否互通的相容性等級">event schema compatibility</a>、<a href="/blog/backend/knowledge-cards/dlq-drain/" data-link-title="DLQ Drain" data-link-desc="說明把 dead-letter queue 累積的訊息重新處理或排空的受控流程">DLQ drain</a> 與 <a href="/blog/backend/knowledge-cards/poison-message-quarantine/" data-link-title="Poison-Message Quarantine" data-link-desc="說明把毒訊息從主處理路徑隔離出來的機制，讓正常訊息繼續前進">poison-message quarantine</a>。這些卡片讓讀者能分辨「queue 有持久化」和「consumer 結果可恢復」分屬不同責任。</p>
<h2 id="實作探討入口">實作探討入口</h2>
<p>佇列的第一條實作路徑是 <a href="/blog/backend/03-message-queue/queue-consumer-retry-replay-handoff/" data-link-title="3.8 Queue Consumer Retry 與 Replay Handoff（實作示範）" data-link-desc="以 order_created consumer 示範 queue 路徑如何交付 idempotency evidence、DLQ handling、replay runbook 與 incident decision log。">3.8 Queue Consumer Retry 與 Replay Handoff（實作示範）</a>。這篇以 <code>order_created</code> consumer 為例，說明 idempotency evidence、DLQ handling、replay runbook 與 incident decision route 如何一起成立。</p>
<p>這條路徑的前置引用應該是 3.2 durable queue、3.3 outbox pattern、3.4 consumer design、<a href="/blog/backend/06-reliability/idempotency-replay/" data-link-title="6.12 Idempotency 與 Replay 驗證" data-link-desc="把重試、重播與冪等性從口頭約定變成可驗證屬性">6.12 Idempotency 與 Replay 驗證</a> 與 <a href="/blog/backend/06-reliability/verification-evidence-handoff/" data-link-title="6.23 Verification Evidence Handoff" data-link-desc="把 SLO、load、chaos、DR 與 readiness 結果包成 release / incident 可用證據">6.23 Verification Evidence Handoff</a>。完成後可依 <a href="/blog/backend/#%e5%ad%b8%e7%bf%92%e8%b7%af%e7%b7%9a" data-link-title="Backend 服務實務指南" data-link-desc="用跨語言教學路線整理資料庫、快取、訊息佇列、觀測、部署、可靠性、資安、事故與容量等後端服務能力">Backend 學習路線</a> 進入下一條服務路徑。</p>
<p>佇列路徑的 artifact 對齊重點是「把投遞成功與處理成功拆開記錄」。對 <a href="/blog/backend/04-observability/observability-evidence-package/" data-link-title="4.20 Observability Evidence Package" data-link-desc="把 log、metric、trace、audit 與資料品質限制包成可交接證據">4.20</a> 要交 <code>Source/Time range/Query link/Owner/Data quality</code>，並覆蓋 consumer lag、retry、DLQ 與 duplicate side-effect；對 <a href="/blog/backend/06-reliability/idempotency-replay/" data-link-title="6.12 Idempotency 與 Replay 驗證" data-link-desc="把重試、重播與冪等性從口頭約定變成可驗證屬性">6.12</a> / <a href="/blog/backend/06-reliability/verification-evidence-handoff/" data-link-title="6.23 Verification Evidence Handoff" data-link-desc="把 SLO、load、chaos、DR 與 readiness 結果包成 release / incident 可用證據">6.23</a> / <a href="/blog/backend/06-reliability/release-gate/" data-link-title="6.8 Release Gate 與變更節奏" data-link-desc="把驗證、migration、相容性納入放行判準">6.8</a> 要交 <code>Gate decision/Checks/Stop condition/Rollback window/Owner</code>，呈現 replay 範圍、去重驗證與補償路徑；對 <a href="/blog/backend/08-incident-response/incident-decision-log/" data-link-title="8.19 Incident Decision Log" data-link-desc="把事中假設、決策、證據、回退條件與責任人留下可復盤紀錄">8.19</a> 要交 <code>Timestamp/Decision/Context/Evidence/Owner/Expected effect/Rollback condition</code>，記錄 pause consumer、drain DLQ、重播啟停的決策序列。</p>
]]></content:encoded></item></channel></rss>