商品页显示“有货”,顾客也能加入购物车,点击提交订单却收到 Out of Stock。这不一定是前端缓存错误。MSI 中 Source 的物理数量、Stock 的可售数量、购物车加载时的校验与下单瞬间的校验是不同概念;高并发时,几秒钟就可能产生新的 reservation。

确认网站使用哪个 Stock

SELECT stock_id, type, code
FROM inventory_stock_sales_channel
WHERE type = 'website';

SELECT source_code, sku, quantity, status
FROM inventory_source_item
WHERE sku = 'SKU-001';

另一个 Stock 的 Source 有货,并不能支持当前网站销售。先核对 website code 与 stock_id,再看该 Stock 关联的 Source。商品 source item 的 status 为禁用时,quantity 大于零也不能贡献可售量。

Reservation 是增量,不是当前库存快照

SELECT reservation_id, stock_id, sku, quantity, metadata
FROM inventory_reservation
WHERE sku = 'SKU-001'
ORDER BY reservation_id DESC
LIMIT 30;

下单通常产生负 reservation,取消或退款等流程产生补偿记录。不要把表中负数当“错误”,应按 stock_id 和 SKU 求和后理解。订单状态被自定义流程跳过、消费者未运行或脚本绕过库存 API,都可能留下未补偿 reservation。

使用官方命令列出不一致时,先读输出并关联订单,再创建补偿。不要直接 DELETE reservation,因为它是审计链的一部分。

商品页为什么仍显示有货

商品详情页可能来自 FPC/CDN,库存消息又由自定义接口或旧 stock item 字段提供。可配置商品还可能因另一个子商品有货而显示父级可售,但顾客选中的具体组合已经售罄。检查请求中的 sku 与后台观察的 sku 是否同一个。

结账校验是最后一道并发保护

两名顾客同时看到最后一件商品时,前端不可能永久保证两人都能买到。结账重新验证是正确行为。业务可通过更及时的库存接口、购物车保留策略和清晰提示减少挫败,但不能关闭最终校验。

验证一条完整数量链

记录 Source quantity、reservation 汇总、salable quantity、购物车数量与下单结果;随后取消测试订单,确认补偿写入且可售量恢复。再测试并发两单、可配置子 SKU 和不同网站 Stock。只有数量在每个动作后按预期变化,才说明不是缓存碰巧刷新。

最小销售数量也会伪装成缺货

错误文案如果被主题统一翻译为 Out of Stock,实际可能是最小/最大购买数量、增量步长或购物车已有数量超限。查看接口原始 message 与 quote item qty,不要只相信页面提示。B2B 按客户组配置的数量限制,也要用发生问题的客户身份复现。