把事件當提示,不要當成完整帳簿
Webhook 是外部平台在資料改變後,向企業系統端點發送的通知。它可以快速更新訂單畫面,但收到一個通知,不代表先前的通知全部到齊,也不代表下一個收到的就是下一步。Shopify 明確說明,Webhook 不保證必定送達,也不保證同一主題或不同主題按順序到達。Stripe 同樣指出,事件可能亂序或重複送達。這些是供應商列明的傳送特性,不應當作罕見意外。如果系統假設訊息一定整齊排列,重新發送後便可能把已付款訂單改回未付款,或安排兩次出貨。
設計時要分開三件事:收到的請求是否真實、是否已保存、業務效果是否正確套用。端點回覆成功,只是回應平台今次送達嘗試,不能單憑它證明已扣貨、已開發票或有員工處理例外。公司應設立持久的事件收件紀錄,保存平台及帳戶、事件編號、類別、相關物件、收到時間、處理狀態,並安全地連到原始內容。正式訂單帳則記下已接受的業務狀態轉換。員工畫面應同時顯示現時訂單狀態和未解決的事件,避免只見到一個看似安心的標籤。
核實、保存,再回覆送達
接收端點應依照供應商文件,用未經改動的請求內容核對簽名,然後才信任訊息。驗證不通過便拒絕。通過後,先把事件識別碼及基本處理紀錄寫入持久儲存;以平台、帳戶及事件編號作唯一限制,避免同一個通知重複建立收件紀錄。完成保存後,才按供應商要求回覆已收到。不要在平台等待 HTTP 回覆時,串連多個耗時的外部服務;把業務處理交給工作佇列,令失敗能被員工看見並受控重試。密鑰不應放在文章草稿或日誌,須依正常營運程序管理;原始通知可能包含個人資料,查看權限亦要收窄。
事件編號能分辨同一事件的重送,卻不能解決所有重複業務動作。Stripe 文件指出,有時兩個不同的 Event 物件會涉及相同業務物件及事件類別。因此,出貨指令本身也要有唯一規則,例如同一訂單同一履行階段只建立一次。付款平台可能用不同種類的事件描述同一付款結果;應按訂單目前狀態決定可否轉換,而非按收到通知的次數執行。反過來,也不能把所有意料之外的訊息都當作無害重複,因為它可能代表真正的新變動。收件紀錄讓覆核者有線索分辨,毋須盲目重播。
不要按到達先後推斷訂單進度
假設付款在十時零二分成功,十時零三分又有訂單更新,但系統先收到更新通知。若程式只照到達順序覆寫,較舊的付款通知稍後到達時,可能把較新的訂單畫面改成「待處理」。不能單靠通知上的時間排序解決:Stripe 特別提醒,兩個不同的快照事件可有同一個 created 時間,不能把它當成可靠的事件次序或去重鍵。Shopify 建議用通知時間協助整理,同時建議定期重新擷取正式資料作對帳。實際做法須視乎平台和物件:當狀態轉換影響業務時,向來源平台查詢最新物件,把識別碼及狀態跟本地紀錄比較,再執行允許的轉換。
容許哪些轉換,應由業務負責人與開發人員共同訂明。「付款待定」可能轉為「已付款」、「失敗」或「待覆核」;「已付款」不應只因一個較舊通知出現便退回「待定」。退款是獨立財務動作,取消訂單也不等於收到退回的包裹。每次狀態變更應連到來源事件或明確的人手操作。若暫時查不到平台正式物件,應把訂單列為待覆核,不應猜測。出貨和啟用服務等後果較大的動作,要有相關的已確認狀態,而且本身可以安全地重試。這樣客戶問起為何暫停出貨,員工才有可追溯的答案。
找出從未到達的通知
再好的事件處理程式,也處理不到完全沒有收到的通知。Shopify 因此明確建議定期對帳,因為 Webhook 可能漏送或在接收方處理失敗。對每個平台及重要的業務物件,訂明定期查詢「自上次核實後有變動」紀錄的方法。時間範圍應有適當重疊,分頁亦要穩定,避免剛好落在兩次執行邊界的變動被跳過;重疊範圍再次出現的物件須去重。把來源平台的正式狀態與本地訂單、付款及履行紀錄比較。差異應進入例外清單,列出平台參照、雙方狀態和建議修正,不要暗中直接覆寫。員工可有「重新同步此訂單」功能處理單一求助個案,但仍要遵守同一套安全狀態規則。
只有當一頁或一批資料已可靠處理後,才更新檢查點。工作途中中斷,便重跑尚未提交的部分。監察上次成功執行時間、未解決差異數量、最舊個案,以及平台 API 是否無法使用。這些是營運警號,不是「絕無漏單」的證明。具體查詢取決於平台實際提供甚麼功能:有些可以按更新時間篩選,有些要使用游標或其他物件路徑。須以真實連接測試存取權和查詢限制。平台暫時不可用時,員工畫面要坦白標示資料未核實,並暫緩高風險後續動作,不能把舊狀態裝作最新。
演練通知故障的完整路徑
用非正式訂單演練四種情況:同一個已簽名事件送達兩次、較後狀態先於較早狀態到達、事件已存入收件紀錄但業務更新前處理程式失敗,以及平台 API 看得到交易但收件紀錄完全沒有通知。逐一查看收件箱、訂單歷史、出貨指令和對帳報告。期望結果是每項業務動作只正確執行一次;事實不足時明確列為待處理;重試時亦不會產生第二次效果。還要測試簽名錯誤的請求,確認不會帶來可信的業務變動。測試報告不應貼出真實密鑰或客戶原始資料。
營運團隊應有一張事故處理卡,寫明誰可以暫停出貨、如何查到平台正式物件、通知是否已經記錄、準備進行哪項狀態轉換,以及誰批准人手修正。每次修正要保留舊值、新值和原因。部署新版本或平台改變事件格式後,應檢查例外清單,因為即使 HTTP 端點仍顯示正常,新格式也可能令處理失敗。真正目標是能解釋並修復兩邊紀錄的差異。單看一張全綠色的通知送達圖,店主仍不知道客戶訂單是否只被正確處理一次。
事故發生前,先按影響程度訂下處理門檻。漏了推廣偏好更新、付款確認或出貨指令,後果各有不同,不應一律使用無聲的重試規則。要列明哪些差異須立即暫停履行、哪些可等下一輪對帳,以及哪些需要主動向客戶更正。保留少量已知的測試物件,方便更改端點或權限後核對連接是否正常。平台儀表板可能只顯示送達嘗試,公司收件紀錄則顯示實際接受的事件;調查時要比對兩邊。如需人手重播,記下由誰發起及事前核對了哪個平台物件。重播仍應經正常驗證與狀態轉換,不能用管理捷徑直接把訂單資料表改成「已付款」,否則會抹掉了解故障所需的證據。修復後也要核實後續結果,而不只看畫面:只有一項出貨指令、正確的客戶訊息,而且沒有第二次財務動作。
進行前先確認
- 每個已驗證通知是否先保存平台事件編號才回覆?
- 訂單狀態能否抵受較舊或重複的通知?
- 哪項對帳工作能找出從未經通知到達的變動?


