iT邦幫忙

2026 iThome 鐵人賽

DAY 12
1
Software Development

Re:從零開始做直播代購電商平台系列 第 18 篇

Day 18|通知系統:兩個欄位、一支排程,和一通電話

  • 分享至 

  • xImage
  •  

「通知系統」四個字在教科書裡的長相:一套 notification service、一組 message queue、模板引擎、多渠道 SDK、退避重試框架。這章要講的版本是:兩個欄位、一支排程掃描、一條十秒規則,和客服的一通電話。它小得不像個系統——而它送達了 99% 的通知,剩下的 1% 也有人接。

渠道帳本:成本與嚴重度對齊

先盤點渠道。這個系統的通知走四條路,嚴重度越高、渠道越貴:

三級階梯加一條旁支:越嚴重的訊息走越貴的渠道,最貴的那條靠人。

最值得停的是催付這條線,它是兩段式的。檔期尾聲,先發一次催繳簡訊——簡訊有 API,但一個檔期只用這一次,稀缺渠道省著用的紀律做到了極致;簡訊沒催動的,才進客服電話:再不付款單就要被清、人要進黑名單,這種最後通牒交給任何自動渠道都不夠——private reply 有政策牆(FB 規定一則留言只能回一次,得標通知已經用掉了),email 會沉底,必達的訊息只有電話。而無論簡訊還是電話,前提都是有號碼——所以當年做了「綁定電話送免運」的活動,很多客人綁了。用運費採購一條高觸達渠道,順便給簡訊 OTP 鋪路——觸達權是稀缺資產,它不是接了 API 就有,是產品拿東西換來的。這是我在這個系統裡最喜歡的增長設計之一。

沒有隊列的通知隊列

得標通知怎麼發?教科書會畫一條 message queue。當年的答案是:不需要隊列,因為事實表就是隊列。

掃表就是取件、欄位就是投遞帳:兩個欄位換掉一套 message queue 加 notification service。

流程一句話講完:喊單會 upsert fbmsgtocartitem,排程掃這張表裡已結標、未成功、重試不滿 5 次的列,打 FB 的 batch API 發得標通知(附綁定 token),回頭更新成功欄位或重試次數。成功、或重試滿 5 次,就是終態——有界的 at-least-once,不會有殭屍任務永遠重試。

這個設計的好,要跟教科書版對照才顯出來:多數團隊會為這個需求上一套 MQ + notification service + 投遞狀態表——三個新元件、三處新的一致性邊界。這裡是兩個欄位:隊列就是掃表的 WHERE 條件、投遞帳就是欄位本身,而「這位客人收到通知了嗎」是一句 SQL,不是跨三個系統的追蹤。fbmsgtocartitem 至此有了五重身分:訂單溯源、LWW 的 upsert 目標、通知隊列、投遞帳、對帳錨點——一張表五個角色而不勉強,因為每個角色只讀寫自己的欄位,而它們共享同一個事實粒度:一則留言一列。

戰記:被 FB 文件坑的那次限速

這章唯一的事故。一開始發通知是一則一則打 FB API——然後被限速了,得標通知大塞車,客人在留言區問「怎麼還沒收到」,主播罵死。

最嘔的是:打的量明明離 FB 文件寫的速率上限還很遠。對著文件檢查了半天,沒有超,但就是被限。最後的修法是改用 batch API 一次打包,從此穩定,送達率 99%——剩下那 1% 是無論如何都寄不出去的帳號(FB 端的因素),靠客服補。

教訓兩條:外部平台的文件是參考值,不是 SLA——真實限額只能實測,尤其當你的流量模式(直播結標瞬間的爆發)跟平台想像的不一樣時;以及**「發不出去」必須是可見的狀態**——表上那個成功欄位,讓 1% 的殘量有地方可查、有人可接,而不是無聲蒸發。這跟留言章「失敗略過」的教訓遙相呼應:當年在留言那頭學到的課,在通知這頭做對了。

三條小規則,省掉一個系統

這章剩下的部分,是三條各自省掉一個子系統的規則:

  • 10 秒規則。 任何超過 10 秒的操作,一律做成 async task+完成後寄 email 給操作者(例:匯出檔期訂單)。「要不要 async」從逐案的架構討論變成一條常數規則,內部使用者也學會了心智模型:久的事情,信箱見。順帶一提,內部人員登入本來就是公司 email+OTP——通知和認證共用同一條信任鏈,零密碼。
  • 催付名單不是功能,是一次查詢。 客服要打電話催付,名單哪來?後台的訂單/購物車管理頁支援可組合的花式搜尋(Django Ninja 把 filters 組起來),「快結束檔期下的未付 cart item」就是一組查詢條件。通用查詢機制做得夠好,專用清單頁的需求會自己消失——機制歸系統,政策歸人:系統給查詢能力,打給誰、先打誰,客服決定。
  • 站內通知,不做。 站內通知意味著一整套:未讀狀態、通知列表、已讀回報、推播——而 email 已經躺在 Google Workspace 裡。「還不值得自建」是這個團隊反覆展現的判斷力:抽象和基礎設施,等第二個真實需求出現再蓋。

還有一條「不通知」也值得回收:重喊時被清掉舊單的客人,系統不另行通知——主播口播就是通知,系統貼心一分,直播的急迫感就漏一分;重喊後重新喊到的人,照常走得標通知。通知系統的邊界,不只是「發什麼」,也是「刻意不發什麼」。

重來會怎麼做

這是全系列重來清單最短的一章:幾乎原樣保留。兩個欄位的投遞帳、掃表的隊列、渠道分級、10 秒規則,放到今天依然是對的尺寸。真要挑,只有兩件小事:

  1. 「寄不出去」變成客服頁的預設 filter。 殘量已經可查(成功欄位在),重來把它做成一鍵——讓 1% 的名單主動出現在客服眼前,而不是等有人想到去查。
  2. 等第二個渠道再抽象。 如果 LINE、簡訊行銷這些渠道真的要加,才值得立一層通知抽象(渠道介面+統一投遞帳);在那之前,任何「通知中心」都是替想像中的需求蓋房子。

反思

觸達權是買來的,不是接來的

工程師的直覺是「接上 API 就能發通知」——實際上每條渠道都有它的牆:FB 有政策(一則留言回一次、24 小時窗口),email 有沉底,簡訊有成本。真正稀缺的不是發送能力,是對方會看到的權利。「綁定電話送免運」教我的是:觸達權要當資產經營——它可以被購買(免運換號碼)、會折舊(騷擾就失效)、要省著用(電話只留給最後通牒)。通知系統設計的第一問不是「怎麼發」,是**「我憑什麼發,而他為什麼會看」**。

最好的基礎設施,是你沒有蓋的那些

這章從頭到尾在講「沒有蓋的東西」:沒有 message queue(掃表)、沒有 notification service(兩個欄位)、沒有站內通知(email)、沒有催付功能(一次查詢)。每個「沒有」都不是能力不足,是判斷——在需求被證明之前,基礎設施是負債不是資產。而支撐這些「沒有」的,是幾個做得特別紮實的「有」:可組合的查詢、事實粒度正確的表、現成的 Workspace。基礎設施的減法,靠的是地基的加法。

99% 的系統,1% 的人

綁定漏斗收到 99%,通知送達 99%,催付最後靠電話——這個系統到處都是同一個形狀:自動化把大宗收走,把殘量標記出來,交給人。很多工程師把「還有 1% 要人工」當成系統的恥辱,拚命想把它自動化到零;這個系統把 1% 當成設計的一部分:給它欄位、給它查詢、給它一個負責的角色。通知的終點不是「送出」,是「沒送到的,有人接」——把這句換成任何系統都成立:自動化的品質,不在覆蓋率的九有幾個,在殘量落地的姿勢好不好看。

明天講風控與黑名單:不是逐客令,是信用體系。


本文改寫自我的部落格系列《Re:從零開始做直播代購電商平台》,本篇完整版:https://blog.aidan.tw/blog/rezero-notification/


上一篇
Day 17|優惠與金額(下):最優惠組合是 NP-hard 嗎?
下一篇
Day 19|風控與黑名單:不是逐客令,是信用體系
系列文
Re:從零開始做直播代購電商平台 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言