搜尋文件

輸入關鍵字,搜尋標題與正文。

    訊息佇列與事件驅動架構文件 01/12

    同步呼叫與非同步工作邊界

    本文提要

    把耗時工作交給背景程序,會縮短呼叫者等待受理的時間,也會增加一個必須追蹤的交接過程。 要理解訊息佇列,先把「接受意圖」「交付工作」與「完成結果」分開。

    18px · 寬鬆行距

    閱讀設定

    排版預覽 · 示範文字(可捲動)

    檔案與目錄

    Linux 以一棵從根目錄 / 開始的樹狀結構組織檔案。目錄用來整理檔案,也可以包含其他目錄。

    pwd
    ls -la /home
    18px

    16、18、20、22px;隨瀏覽器文字大小縮放。

    欄寬套用於背景文章;此處預覽字級與行距。手機正文自動配合螢幕。

    文件與本文目錄
    本主題文件

    把耗時工作交給背景程序,會縮短呼叫者等待受理的時間,也會增加一個必須追蹤的交接過程。 要理解訊息佇列,先把「接受意圖」「交付工作」與「完成結果」分開。

    本文從文章匯出服務出發,只要求理解一次請求回應與基本資料庫交易。對外操作資源與輪詢方式見長時間執行操作與非同步 API 契約,這裡研究 API 後面的工作如何接續。

    查證日期:2026-11-04。依 RFC 9110 與當日 Microsoft 官方文件整理;所有工作狀態、識別與歷程均為自創概念例子,未部署 broker 或執行故障實驗。

    先從不使用 broker 的版本開始

    假設使用者要求匯出一組文章。同步版本由 API 驗證輸入、產生檔案,最後回傳下載入口。若等待期間連線中斷,使用者可能只看到逾時,卻不知道檔案是否已產生。

    背景版本可以先保存工作 job-42,回傳工作識別,讓 worker 稍後讀取待處理的資料列。這已經把受理與執行分開,並不必然需要獨立的訊息服務。是否增加 broker,應從工作分派、負載緩衝與不同程序協作的需求決定。

    HTTP 的 202 Accepted 只表示已接受處理,不能推論處理一定完成,甚至不能單憑狀態碼保證未來一定執行。更強的受理承諾要由服務契約補上。參考 RFC 9110 §15.3.3。

    本例選擇較強的應用契約:回傳受理成功前,必須持久保存可查詢的工作;工作在依賴恢復且資源足夠時,應走向成功或明確失敗。這是案例需求,並非 202 自動提供的能力。

    引入佇列,是增加一次責任交接

    生產者(producer)建立並送出訊息;訊息代理(broker)依其設定保存、路由或提供訊息;消費者(consumer)讀取訊息並處理。worker 是本例執行匯出的程序,也是工作訊息的 consumer。

    佇列可以把到達速度與處理速度暫時分開。Microsoft 的 Queue-Based Load Leveling 說明以佇列緩衝流量,讓處理端按可承受速率工作。這種緩衝仍受保存期限、容量及處理能力限制,不能把有限資源變成無限容量。參考 Azure:Queue-Based Load Leveling。

    以下歷程中的「發布已確認」暫指 producer 取得 broker 按設定回覆的成功證據;不同產品確認到哪裡,第四篇再拆解。

    表格・3 欄 6 列
    步驟發生的事目前能確認的進度
    1呼叫端以意圖識別 export-intent-7 建立匯出發出了建立請求,受理結果仍未知
    2API 保存 job-42 為 pending工作存在,尚不能證明訊息已交給 broker
    3producer 發布 cmd-42,指向 job-42,取得發布確認依 broker 契約完成交接,尚未證明 worker 開始
    4worker 取得訊息,將工作推進為 running有一次處理嘗試開始,檔案仍可能失敗
    5worker 保存檔案與結果,工作進入 succeeded達到本例定義的匯出完成條件
    6worker 告知 broker 本次投遞可結束broker 的消費進度才接上業務完成進度

    表格是概念歷程,沒有宣稱上述六步共用一個交易。實際上,步驟 2 與 3 的資料庫/broker 雙寫,以及步驟 5 與 6 的效果/確認,正是新增的故障窗口。

    狀態必須對應具體證據

    本例用 pending 表示已受理但尚未確認開始,running 表示有處理嘗試,succeeded 表示檔案已按契約保存且結果可查,failed 表示業務已決定終止。各狀態的寫入者與轉移條件也要明訂;收到第二份訊息不能無條件把已成功工作改回執行中。

    程序停止時,資料庫可能長時間留下 running。因此這個字不能獨自證明 worker 現在仍活著;恢復程序必須查明處理嘗試與結果,依契約重試、核對或終止。單次讀取失敗也不應立即被寫成永久的業務失敗。

    三個停止點,檢查非同步增加的責任

    表格・3 欄 3 列
    停止點可能留下的狀態設計必須回答的問題
    保存工作後、發布前有 pending 工作,沒有可消費訊息誰能找出並補交?只等待 worker 不會自行修復
    broker 接受後、producer 收到確認前訊息可能存在,producer 結果未知重送如何辨認同一命令,避免另建工作?
    效果保存後、消費確認前工作已成功,訊息仍可能再次出現下一個 worker 如何辨認已完成效果?

    第一個缺口不能靠調整 consumer ack 解決;第三個也不能靠「producer 發布成功」解決。先保存工作再發訊息與先發訊息再保存工作,只是改變故障窗口,沒有消除跨系統原子性問題。後續的資料庫與訊息原子缺口篇會展開 Outbox;本篇只確認這個問題仍存在。

    重送的基本條件可回查從重送請求到冪等副作用:識別、去重紀錄與業務變更必須在適用範圍內一致處理。佇列本身不替應用保存這些業務規則。

    緩衝之後,壓力仍然需要出口

    假設每秒進來 12 個工作,worker 合計每秒只能完成 10 個,且持續一分鐘都沒有失敗與重試,則積壓增加 2 × 60 = 120 個。這是明列假設的計算,並非產品效能數據。

    若流入長期大於流出,新增佇列只會延後暴露問題。服務仍需控制受理量、並行度、等待期限與過期工作,並告訴使用者何時無法履行受理承諾。相關原理見過載、時間預算與背壓。

    讀完本篇,應能指出:受理成功、訊息已交接、工作已完成是三個不同觀察點。下一篇會替傳遞的內容命名,區分命令、工作與事件。

    相關文件