🎯 什麼情境該想到我

當你「想把一包資料本身傳給接收方,讓對方自行決定怎麼處理」的時候。

⚙️ 怎麼用(步驟 / 公式)

意圖:用文件訊息可靠地把一份資料從一個應用傳到另一個。

做法要點:

  • 訊息本體承載的是「資料本身」,不指定接收方要做什麼動作(與命令訊息的差別)。
  • 關注點是資料的內容與完整送達,而非時效性(與事件訊息的差別)。
  • 常用點對點通道,把單一份資料交給接收者,由對方決定用途。

★ 三種語義裡最容易被忽略的一種,但它其實最常用

命令:「請做 X」            → 有意圖,恰好一個接收者
事件:「X 已經發生」        → 是事實,零到多個接收者
★ 文件:「這是資料,你自己決定要不要用、怎麼用」  → 無意圖

★ 實務上大量的訊息其實是文件訊息,只是被誤稱為事件:

// ★ 這是文件訊息,不是事件 —— 它只是在傳一份資料
type PriceList struct {
    EffectiveFrom time.Time
    Items         []PriceItem
}
// ★ 這才是事件 —— 它宣告了一件已發生的事
type PriceListPublished struct {
    ListID        string
    EffectiveFrom time.Time
}

★ 判準:這則訊息有沒有「時間點」的語義?
有(某件事在某個時刻發生了)→ 事件。
沒有(只是「目前的樣子」)→ 文件訊息。

★★ 文件訊息最重要的特性:它天然適合「最新的才算」

// ★ 文件訊息通常可以用「壓實(compaction)」—— 同一個 key 只留最新一份
// Kafka 的 log compaction 正是為這種訊息設計的:
//   cleanup.policy=compact
//   → 同一個 key 的舊訊息會被清掉,只保留最後一則
//   → ★ 新的消費者從頭讀,就能得到「所有 key 的當前狀態」

★★ 這是 Kafka 一個常被忽略但極有用的能力:
壓實過的 topic 等於「一份可以重播的 key-value 快照」。
參考資料(幣別表、商品目錄、feature flag)用它非常合適。

⚠️ 對照:事件通道不可以壓實。
事件是歷史事實,OrderPlaced 和 OrderCanceled 都必須保留——
壓實會把歷史吃掉。所以「這個通道能不能壓實」是一個很好的檢驗:
能 → 它是文件訊息;不能 → 它是事件。

★ 文件訊息的三個實務用途

用途例子
★ 參考資料同步幣別表、稅率表、商品目錄、feature flag → ★ 配 compaction
★ 回覆內容請求-回覆 的回覆本身通常是文件訊息
★ 資料交付「這是你要的報表資料」——常配 寄物單(大 payload 放物件儲存)

★ 兩個常見錯誤

// ❌ ① 把文件訊息當事件用,於是消費者不知道該不該動作
type Inventory struct{ SKU string; Qty int }
//    → 消費者收到 Qty: 0 —— 是「賣完了」還是「初始化」還是「資料錯了」?
// ✅ 要動作就發事件(StockDepleted),要同步狀態就發文件並說清楚語義
 
// ❌ ② 文件訊息沒有版本/時間戳 → 亂序時舊的蓋掉新的
type PriceList struct{ Items []PriceItem }
// ✅
type PriceList struct {
    Version int64     `json:"version"`      // ★ 消費端:version <= stored 就丟棄
    AsOf    time.Time `json:"as_of"`
    Items   []PriceItem
}

★ 第②點在文件訊息上特別致命:事件亂序通常只是順序怪,
文件訊息亂序會直接讓狀態退回舊值,而且不會有任何錯誤。

★ 兄弟辨析

差別
命令訊息有意圖、可被拒絕、恰好一個接收者
事件訊息★ 有「時間點」語義;文件訊息只是「目前的樣子」
寄物單文件很大時,只傳位址
資料傳輸物件★ 行程內/跨層的同一想法(純資料、無行為)

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 接收端自行決定如何運用,發送端不掌控後續處理。

  • 重視內容正確與完整;時效性較不是重點。

  • 若重點是「事情發生的通知」而非資料本身,改用事件訊息。

  • ★★ 文件訊息亂序會讓狀態退回舊值,而且不會有任何錯誤。一定要帶 Version/AsOf 並在消費端丟棄過舊的。

  • ★ 判準:有沒有「時間點」語義? 有 → 事件;只是「目前的樣子」→ 文件訊息。

  • ★ 「這個通道能不能壓實」是很好的檢驗:能 → 文件訊息;不能 → 事件(壓實會吃掉歷史)。

  • ★ 不要把文件訊息當事件用。消費者會不知道該不該動作(Qty: 0 是賣完還是初始化?)。

  • 文件訊息通常比事件大,超過 broker 上限要用 寄物單。

  • 參考資料用 compaction 很合適,但要注意:壓實的 topic 沒有「刪除」概念,要用 tombstone(value=null)。

  • 文件訊息也需要冪等——雖然它通常天然冪等(覆寫),但「覆寫成舊值」仍是錯的。

🔗 相關工具