把社区发帖、回帖、积分三个接口串成一条线后,我发现回调地狱比代码更折磨人
上周终于把自家CMS和社区论坛的联动打通了,不是简单的单点登录,是把发帖、回帖、积分变动这三个接口串成了一条完整的业务流。现在用户在我CMS前端发文章,能同步到社区对应版块;在社区回帖,积分能实时累加到CMS的用户中心。听起来挺美好是吧?实际踩坑过程让我想把键盘吃了。
先说发帖接口。社区那边给的是RESTful文档,我CMS用的是ThinkPHP6,一开始图省事直接用`Http::post`裸调。结果社区返回201,我这边也提示"发布成功",但用户刷新社区页面死活找不到帖子。抓包一看,社区接口是异步落库的,201只代表"我收到了",不代表"我存完了"。文档里这行小字藏在页面最底下,字号比蚂蚁还小。后来加了轮询查询接口,根据返回的`task_id`去查最终状态,才算把"伪成功"这个问题掐掉。
回帖接口更阴间。社区那边要求传`thread_id`和`parent_id`,我CMS的评论表设计是嵌套集模型,存的是`ancestor`路径。两边数据结构完全不兼容,我愣是写了个递归函数把路径转成社区要的扁平结构。最坑的是`parent_id`传0和传null,社区处理逻辑不一样:0是顶级回复,null直接被拒。我因为数据库默认值设的是null,测试时回帖成功率50%,完全随机,排查两小时才发现这个破事。
积分接口才是重头戏。社区积分变动有四种场景:发帖奖励、回帖奖励、被点赞奖励、每日签到。每种场景的`event_type`不一样,回调payload的结构也不同。我一开始想偷懒,写了个万能解析方法,结果上线第一天就串了:用户签到积分算到了发帖奖励里,因为两个回调都有`user_id`和`points`字段,我靠字段存在性判断类型,恰好那两个字段重叠。后来老老实实上了策略模式,每种`event_type`对应一个独立处理器,代码多了几十行,但再也不怕字段撞车。
还有个时序坑。用户快速连续回帖,社区回调是按触发时间发的,但网络抖动导致我先收到第二条、后收到第一条。积分累计如果直接`+=$points`,顺序乱了数据就错。我在本地Redis里给每个用户加了积分变动的有序集合,按社区回调里的`event_time`排序,再逐个消费。相当于在自家系统里又做了一层缓冲,社区那边只管发,我这边保证最终一致性。
现在这套联动跑了一周,日志里还有偶尔的超时重试。我把所有接口调用都记了流水表,包括请求体、响应体、耗时、重试次数,出问题至少能甩出证据链。之前没记日志那次,社区运营说我吞积分,我空口白牙解释半天,现在直接把流水ID拍过去,省了多少口水。
有也在折腾多系统联动的老哥吗?你们积分到账是同步阻塞还是异步队列?我现在的方案是接口调用走异步队列,但查询状态用同步轮询,感觉还是有点别扭,想听听更优雅的玩法。