Pomelo中一次RPC调用被多次执行

每次遇到很久调试不出来的bug,都觉得这个bug只要解决了,以后的「你调过的最难调的bug是哪个?」这个问题就有答案了。但是最后找到的原因都是很弱智的错误。

这个bug由来已久,大约两个月之前出现的。在新玩家加入游戏的时候,会给场景内的玩家推送一条onJoin消息。告诉其他玩家这个新人的信息。

后来为了方便做假用户,就另外写了一个入口,供机器人登录,登录后会给所有场景的玩家广播一条onJoin,也去掉了一些玩家需要的信息和游戏逻辑,机器人只是出现在游戏场景里,并不会留下游戏记录。

但是随即出现了一个bug,就是机器人的onJoin总是会重复发好几次。不过问题并不大,因为客户端用的是一个id做key的HashTable来保存玩家信息,多次加入新玩家并不会产生重复。再加上其他需求也很紧,这个问题就放下了。

最近改了一下需求,机器人不再换用不同的账号登录了,而是改用一个账号反复进出,这就产生了新的问题。就是退出场景的onLeave也会发多次。以前一个用户退出场景之后,再多发onLeave,也没关系。现在这个用户退出之后又加入了,再多发一次onLeave,就真的退出了。


确定要改这个bug之后,就加了很多日志来定位位置。开始怀疑是pomelo robot的客户端发起了多次请求,查过日志之后排除了。后来发现,用户加入的时候会连接到connector上,然后connector调用RPC,在后端的remote组件里给其他用户广播onJoin信息,问题就出现在这里。connector只调用了一次RPC,但是remote组件被调用了很多次。

Google了一下发现没有同类的问题,Github上也没有相关的issue。只好自己读代码,和RPC相关的代码在一个叫做pomelo-rpc的module里,以前从来没有读过,还好Wiki比较详细。读了一下代码,又对照日志,发现原来是RPC调用timeout了会重试的。timeout的时候确实会打日志,但是因为不会马上重试,所以中间一般会隔几百上千条日志,以前我就没有把timeout和重发onJoin联系起来。这次在开发机上调试,只有一个用户在里面,日志比较少我才看到。

那么,为什么会timeout呢?原因是调用RPC的时候会传入一个callback,RPC Server执行完以后可以把数据返回给RPC Client。以前普通用户登录的时候,返回的数据是当前场景的其它用户,改成机器人之后,它并不需要知道其它用户的信息,就把callback去掉了。但是没有执行callback,RPC Server就不会告诉RPC client调用已经完成了。client等了一段时间以后,就自动重试了。

解决的方法也很简单,在remote方法的参数最后加一个cb参数,然后最后增加一个cb();就可以了。

标签: nodejs, pomelo

已有 2 条评论

  1. 看不穿 看不穿

    你好,请问你们服务器用的是pomelo框架吗?在使用过程中有没有深坑,最终项目有没有上线验证,谢谢。

    1. 没有上线,开发过程还算顺利,性能也不错。

添加新评论