首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >商品缺货了怎么通知买家才不漏不轰:订阅登记、去重与批量推送

商品缺货了怎么通知买家才不漏不轰:订阅登记、去重与批量推送

原创
作者头像
用户5598620
发布于 2026-09-28 14:00:29
发布于 2026-09-28 14:00:29
50
举报

用户来问"XX 什么时候有货"是商城客服最重复的工作;做了到货通知又怕同一条消息给同一个人发好几遍、几百人同时到货时把通道打爆。读完你能拿到一套"订阅登记 + 去重 + 批量限流 + 失败补发"的可落地设计,附可直接抄走的表结构与处理流程。

一、缺货订阅先解决"谁能收到通知":订阅表与唯一约束

到货通知的第一步是登记订阅关系,核心问题是"一个商品 + 一个用户只能有一条有效订阅"。用唯一索引兜底,状态机区分订阅生命周期:

代码语言:sql
复制
CREATE TABLE stock_subscribe (
  id          BIGINT PRIMARY KEY AUTO_INCREMENT,
  spu_id      BIGINT NOT NULL,
  sku_id      BIGINT NOT NULL,
  user_id     BIGINT NOT NULL,
  status      VARCHAR(16) NOT NULL DEFAULT 'WAITING', -- WAITING/NOTIFIED/CANCELLED/EXPIRED
  created_at  DATETIME NOT NULL,
  notified_at DATETIME,
  UNIQUE KEY uk_sub (sku_id, user_id, status)  -- 唯一键要带上 status 维度
);

为什么唯一键要带 status?因为同一用户可能"等到了没买、过几天又没货了再订阅一次",如果不区分状态,第二次订阅会撞唯一键直接失败。正确做法是:新订阅先看是否存在 WAITING 记录,存在则复用,不存在才插入——把"重复订阅"变成"幂等复用"。

二、到货事件怎么触发:实时事件加定时扫描兜底

到货信号来自两个地方:库存变更的实时事件(入库、退货回仓、调拨到店)和定时扫描兜底(事件丢了、库存手工改数)。实时路径用消息队列解耦:

代码语言:json
复制
{ "event": "stock.in", "skuId": 1001, "qty": 50, "source": "purchase_order" }

消费端收到事件后按 sku 聚合待通知用户。定时扫描兜底每天跑一次,把"库存大于 0 且存在 WAITING 订阅"的 SKU 捞出来补触发,保证事件链路出问题时通知不会永久漏掉:

代码语言:sql
复制
SELECT DISTINCT s.sku_id
FROM stock_subscribe s
JOIN sku_stock st ON st.sku_id = s.sku_id
WHERE s.status = 'WAITING' AND st.available_qty > 0;

捞出的 SKU 走同一套通知流程,生成独立的批次号与实时事件区分开,靠通知幂等表保证两边不会重复发。

三、同一买家重复订阅、重复通知怎么防

重复通知的源头有两个:同一用户在不同入口重复订阅;同一批用户被事件和扫描各触发一次。订阅侧靠唯一索引 + 幂等复用;通知侧靠"通知流水表 + 唯一键":

代码语言:sql
复制
CREATE TABLE stock_notice_log (
  id         BIGINT PRIMARY KEY AUTO_INCREMENT,
  sku_id     BIGINT NOT NULL,
  user_id    BIGINT NOT NULL,
  batch_no   VARCHAR(32) NOT NULL,   -- 本次到货批次号
  status     VARCHAR(16) NOT NULL DEFAULT 'PENDING', -- PENDING/SENT/FAILED/MANUAL
  sent_at    DATETIME,
  UNIQUE KEY uk_notice (sku_id, user_id, batch_no)
);

每个 SKU 每轮到货生成一个 batch_no,同一用户对该批次只允许一条通知记录,插入冲突即跳过——事件和扫描即使重复触发,也只会发一次。用户主动取消订阅时把 status 置 CANCELLED,而不是删除行:删除后同一用户再次订阅会新建记录,历史通知关系就断了;保留状态才能让"订阅-通知-取消-再订阅"形成完整闭环。

四、几百人同时到货怎么推送不崩:批量分片与限流

到货是"一对多"突发流量:一个 SKU 可能几百人订阅,同时触发。逐条调用推送接口会瞬间打爆短信或订阅消息通道。做法是分片批量 + 退避限流:

代码语言:bash
复制
# 伪代码示意:按 100 一批分片,每批间隔退避
for batch in split(waiting_users, 100):
    push_batch(batch)          # 走批量接口
    sleep(backoff_ms)          # 通道限速

同一用户同时订阅了多个 SKU、多轮到货撞在一起时,还要做"用户维度合并":把同一用户当轮所有到货商品合并成一条消息推送,而不是一件商品一条通知。合并推送既省通道资源,也避免用户被频繁打扰。

多实例部署时还要防"多个实例同时推同一个批次":通知流水表的 uk_notice 唯一键天然是抢占锁,谁先插入成功谁推送,其余实例插入冲突即跳过,不需要额外引分布式锁。

五、通知发失败了怎么补发

推送失败要区分对待:通道类失败(限流、超时)可退避重试;权限类失败(用户关闭订阅权限)直接标记不可达。失败记录留在通知流水里,状态置 FAILED 并记录重试次数:

重试策略:失败后按 1 分钟、5 分钟、30 分钟退避重试,至多 3 次;仍失败则标记 MANUAL,运营后台可手动补发;用户主动关闭订阅的标记 CANCELLED,不再进入任何批次。

补发必须按 batch_no 幂等,防止重试成功后又与下一轮批次重复。手动补发的目标用户从通知流水里按批次过滤,避免把已标记取消的用户重复纳入。

踩坑清单

  • 订阅唯一键不带 status,用户第二次订阅直接撞键失败;
  • 只做事件触发不做扫描兜底,事件丢失后到货永远不通知;
  • 通知不做幂等表,事件和扫描重复触发导致同一条消息发两遍;
  • 到货一次性全量逐条推送,通道被打爆、大量失败;
  • 多 SKU 到货不合并,一个用户同时收七八条消息被投诉;
  • 失败重试不做退避,短时间高频重试加剧通道故障。

工程落地建议

到货通知本质是"订阅关系 + 幂等通知 + 批量投递"三件事,不依赖特定框架:订阅关系用唯一索引与状态机管,通知用批号幂等表去重,投递用分片与限流保护通道。先确认自己的订阅模型有没有唯一约束、通知有没有幂等键,再逐步加批量与合并。本文方案仅作技术分享,具体实现按自身业务取舍。

上线复盘清单

  • 订阅表是否有 sku + user 维度的唯一约束,状态机是否覆盖 WAITING/NOTIFIED/CANCELLED
  • 到货触发是否有实时事件加定时扫描双重保障
  • 通知是否按批次幂等去重,事件与扫描重复触发是否只发一次
  • 大批量到货是否分片限流,通道是否设置了退避
  • 同一用户多 SKU 到货是否合并为一条消息
  • 失败重试是否有次数上限与手动补发入口

常见问题

Q:商品缺货后,怎么通知买家到货?

A:先登记"商品 + 用户"订阅关系,库存到货时按 SKU 触发通知,同一用户同一批次只发一次,失败自动退避重试。

Q:同一买家重复订阅缺货提醒,怎么保证只发一次?

A:订阅表按商品与用户建唯一索引,重复订阅幂等复用;通知侧按"商品 + 用户 + 批次号"建唯一记录,重复触发直接跳过。

Q:几百人同时订阅到货,怎么推送不崩不漏?

A:按固定数量分片批量推送,批间加退避限流;同一用户多件到货合并成一条消息;失败按退避重试并记录次数。

Q:到货通知发失败了,用户还能收到吗?

A:通道类失败自动退避重试至多 3 次,仍失败进入手动补发队列;用户关闭订阅的标记取消,不再进入后续批次。

结语

到货通知做不好,要么漏通知得罪买家,要么重复轰炸被投诉。把订阅唯一约束、批次幂等和批量限流立住,两边都稳。仅作技术分享。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、缺货订阅先解决"谁能收到通知":订阅表与唯一约束
  • 二、到货事件怎么触发:实时事件加定时扫描兜底
  • 三、同一买家重复订阅、重复通知怎么防
  • 四、几百人同时到货怎么推送不崩:批量分片与限流
  • 五、通知发失败了怎么补发
  • 踩坑清单
  • 工程落地建议
  • 上线复盘清单
  • 常见问题
  • 结语
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档