門市與市集平台
不要讓最後一件貨賣兩次
一個貨倉,兩個門面。網店同市集平台各自以為手上尚有最後一件,於是兩邊都賣出去。單靠事件通知拉不齊兩邊,因為漏收或重收一次,數字就已經改了,而且改不回來。真正撐得住的,是定時重讀兩邊的排程,加上一種「數字不符就拒絕寫入」的寫法。
- 觸發
- 兩個
- 執行頻率
- 每 10 分鐘
- 工具
- 4 件
- 需要 durable execution
- 需要
流程
上面那條記錄這一單造成的變動,下面那條定時重讀兩邊,只有在數字不符時才寫入。
有訂單進來
Shopify Admin API
算出新的數量
n8n · Make
寫入庫存流水
Sheets · Airtable
每 10 分鐘
n8n 排程
讀取兩邊
n8n
數字是否不符?
n8n IF
寫入數量,並附比對值
Shopify Admin API
不作處理
—
逐步拆解
- 01
有訂單進來
Shopify Admin API成交一刻 webhook 觸發。把它當成「有嘢郁過」的提示,而不是當成庫存數字本身。
- 02
算出新的數量
n8n · Make以最後讀到的數量為基準扣減,並以訂單編號做鎖。扣兩次不可能靠再扣一次還原——這一步必須在中途當機之後仍然只算一次,所以 durable execution 在這裡不是選項。
- 03
寫入庫存流水
Sheets · Airtable每一次變動一行,附訂單編號。兩邊數字不符時,用來對數的是這條流水,不是任何一個門面。
- 04
每 10 分鐘
n8n 排程對數的一輪。無論有沒有收到 webhook 都會跑——重點正正在此:一個從來沒有送到的 webhook,不會留下任何可以察覺的痕跡。
- 05
讀取兩邊
n8n取回網店同市集平台的即時數量,以及流水上最後一個數。
- 06
數字是否不符?
n8n IF三個數一齊比。只要不是完全一致,就代表有變動漏了、重複了,或者次序調轉了。
- 07
寫入數量,並附比對值
Shopify Admin API寫入絕對數量,同時傳入你預期見到的數。如果在你讀取之後那幾秒有人下單,這次寫入會失敗,而不是把那一單覆蓋掉。
平台不容許的事
上面的設計不是個人偏好。每一部分都是因為 Shopify 文件上寫明的行為,才要那樣做。
inventorySetQuantities 寫入的是絕對數量,並接受 compareQuantity——只有現存數值仍然相符,這次寫入才會生效。Shopify 對「略過比對」的說明是:多個請求同時發生時,「can lead to inaccurate inventory quantities」。
Shopify Admin GraphQL API — inventorySetQuantitiesWebhook 的送達「isn't always guaranteed」,而且 Shopify「doesn't guarantee ordering within a topic, or across different topics for the same resource」。文件本身給的做法,就是定期重新取數的對數程序——即是這個流程下面那一條。
Shopify — About webhooks (best practices)Shopify 給一秒連線、五秒完成整個請求。收不到回應會在四小時內重試八次;連續八次失敗之後,經 Admin API 建立的訂閱會被自動刪除——即是說,端點在周末停了兩日,回來時可能連訂閱都沒有了。
Shopify — Deliver webhooks through HTTPSGraphQL Admin API 計的是查詢成本,不是請求次數:標準方案每秒 100 點,單一查詢不得超過 1,000 點。一次過讀取全部 SKU 的對數程序,會先撞上點數上限,而不是次數上限。
Shopify — API rate limits
什麼情況不值得做
以下三種情況,維護成本會高於超賣的代價。
你做的是接單後生產,或者存貨深度足夠,最後一件從來不會被爭。整個流程就是為那最後一件而存在;沒有這個壓力,它只是一套守著空氣的機器。
兩個渠道本身不共用同一個貨倉。各自有各自的配額,就不存在「不同步」;硬要用同一個數字去管,反而製造出它本來想防的衝突。
沒有人負責處理差異。對數程序發現數字不符時,總要有人判斷是流水對,還是門面對。沒有這個人,流程只會每十分鐘寫一個數,而沒有人知道錯是向哪一邊偏。