上周末参加了一个同行的技术沙龙,有个做美业 SaaS 的研发总监在茶歇时大吐苦水:“双十一我们搞了个‘大客扫码自动建 VVIP 群’的活动。结果刚上线就炸了,同一个大客扫码,系统在企微里瞬间拉了 3 个名字一模一样的专属群,把客户和门店店长全拉进去了。客户当场发飙,以为我们的系统被黑客劫持了。”

我一听这症状,连他的代码都不用看,直接一针见血:“你们的 Webhook 接收层,绝对没有给‘群新增事件’做幂等(去重)处理。”

作为在一线高频对接各类企微 API(机器人)开发团队的销售客服,我发现 80% 的研发兄弟在处理群聊事件时,依然抱着一种极度天真的“单机思维”——认为企微网关推一次,我收一次,绝对不可能多。

今天咱们直接基于 星云API xingyapi.com 的底层架构,把“群新增事件的重复推送”这个极其隐蔽、杀伤力却极大的分布式大坑彻底刨开。

认清现实:企微底层网关的投递哲学

首先,你必须理解企微网关在 Webhook 推送上的核心价值观:“宁可错杀一千(重复推送),绝不放过一个(丢失消息)”

在公网环境下,这套被称作“At-least-once(至少投递一次)”的机制是极其残酷的。当一个新群被创建,或者有新成员加入时,底层网关会向你的服务器发起 HTTP POST 请求。

此时,网关最多只等你 5 秒钟

如果你的服务器因为 CPU 满载、网络抖动,或者你的代码在接收线程里去调了查数据库的慢 SQL,导致没能在 5 秒内返回 HTTP 200 + "success"。网关就会无情地判定:“这孙子没收到!”

紧接着,网关会立刻发起第二次、第三次重试。这种重试在业务高峰期,几乎是 100% 会发生的常态。

为什么“群新增”事件是重灾区?

有些研发可能会纳闷:普通文本消息也会重试,为什么建群事件的破坏力这么大?

因为群新增(建群)在业务侧是一个极度“沉重”的动作。

当你的路由层捕获到群创建事件时,你的后台往往需要做一系列极其耗时的连环操作:

  1. 去数据库建立新的群档案记录。

  2. 调用 API 获取群成员详细列表。

  3. 调用 AI 大模型生成专属的入群欢迎语。

  4. 调用发消息接口下发多媒体卡片。

实战 JSON 载荷(群新增事件):

JSON

{
    "MsgType": "event",
    "Event": "change_external_chat",
    "ChangeType": "create", // 致命触发点:群创建
    "ChatId": "wr_xxxxxxxxxxxxxxxxxxxx", 
    "CreateTime": 1698765432
}

如果你没有做去重,网关重试了 3 次,你的系统就会把上述这套沉重的业务逻辑硬生生跑 3 遍!轻则在群里连发 3 条一样的欢迎语,重则直接导致数据库死锁或者脏数据横飞(比如开篇那个拉了 3 个重复群的惨案,就是因为触发条件被重复执行了)。

铸造防重装甲:Redis 分布式锁实战

要应对这种不讲理的重复推送,我们在 Webhook 接收端必须构建一道“幂等过滤网”。对于事件类报文,由于它没有普通消息那种 clientMsgId,我们需要自己组装唯一指纹。

实战防御逻辑:

  1. 提取唯一指纹(DNA):拿到 JSON 后,立刻将 ChatId + Event + ChangeType + CreateTime 拼接起来,算一个 MD5。这个 MD5 就是这个新增事件的绝对唯一标识。

  2. SETNX 抢占式锁:拿着这个 MD5 去 Redis 里执行 SETNX(如果不存在则设置),过期时间设为 10 分钟(足以覆盖网关的重试周期)。

  3. 生死判决

    • 如果 Redis 返回 1(抢锁成功):说明这是第一次收到这个建群事件,立刻扔进 MQ 队列,让消费者去慢慢建档案、发欢迎语。

    • 如果 Redis 返回 0(抢锁失败):说明这是网关超时重发过来的“幽灵报文”!此时立刻中断业务,直接向网关返回 success。假装自己已经处理了,安抚网关停止重试。

这套逻辑必须在解密报文后的第一行代码就执行,绝对不能拖泥带水。

老兵的极限施压联调法

防重代码写起来不到 10 行,但如果没有经过高并发的毒打,你永远不知道锁有没有写对。

在把代码合入主干前,我强烈要求团队里的所有人必须使用 Apifox 或者 Apipost 进行极限施压:

  1. 本地起好带有 Redis 锁的接收端服务。

  2. 在 Apifox 里,构造一个标准的 ChangeType: create 的群新增测试 JSON。

  3. 打开工具的性能测试/并发压测模块,设置 50 个并发线程,在 1 秒内把这个一模一样的 JSON 疯狂砸向你的本地接口。

  4. 去看你的本地数据库和日志:如果你的业务流转日志只打印了 1 次,数据库里只建了 1 个群档案,另外 49 次全被 Redis 锁拦截并平滑返回了 200,那么恭喜你,你的系统彻底“刀枪不入”了。

真正的企业级架构师,从来不假设网络是百分百可靠的。拥抱乱序、容忍重试,把幂等防重机制刻进每一个 Webhook 路由的基因里,你的企微自动化系统才能在流量洪峰中活下来。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐