首页 > 其他 > 详细

基于Plan_txtMsg发消息bug复盘

时间:2019-08-22 13:34:43      阅读:103      评论:0      收藏:0      [点我收藏+]

bug表现为:

  1. 已经基于Plan_txtMsg给用户发送了消息,但pushmsgid的值并没有回填
  2. 因为pushmsgid的值没有回填,理论上会有至多三次的发送,但是消息重复一直发送了

问题排查过程

  1. 了解发送业务,搞清楚了发送都会走一个统一入口Plan_txtMsg实体的send方法
  2. 进入Plan_txtMsg实体,阅读send方法
  3. 发现了bug表现2的原因:fixPushMsgId需要传入的参数是PushMsg实体,但是在发送失败的调用中传入的参数却是数字
    1. 技术分享图片
  4. 继续阅读代码,明确表现1的问题就是没有返回PushMsg实体,但是层层追代码,感觉PushMsg实体应该是返回的
  5. 对send方法各条件分支打log,并修复了表现2
    1. 技术分享图片
  6. 线上监控log,发现log没有打出来。排查后发现cron_plan_txtmsg.php脚本并未开启xworklog日志的刷新
    1. 技术分享图片
  7. 开启后再次上线。继续监控线上日志,得到了我们之前打的日志。发现的确有PushMsg实体不存在的情况
  8. 日志坚定了我把问题定位到没有返回PushMsg实体的决心。也就是把问题定位到了sendTxtMsgToPatientByAuditor方法
    public static function sendTxtMsgToPatientByAuditor(Patient $patient, Auditor $auditor, $content, $appendarr = array()) {
        $wxusers = WxUserDao::getListByPatient($patient);
     
        $pushmsg = null;
        $appendarr[‘unitid‘] = Pipe::getUnitidMD5($patient->id);
        foreach ($wxusers as $wxuser) {
            $pushmsg = self::sendTxtMsgToWxUserByAuditor($wxuser, $auditor, $content, $appendarr) ?? $pushmsg;
        }
     
        return $pushmsg;
    }
     
    public static function sendTxtMsgToWxUserByAuditor(WxUser $wxuser, Auditor $auditor, $content, $appendarr = array()) {
        if ($wxuser->isFromMiniProgram()) {
            return false;
        }
     
        $appendarr = self::setSendByObj($auditor, $appendarr);
        return WechatMsg::sendmsg2wxuser($wxuser, $content, $appendarr);
    }

     

  9. 查看上述代码发现在foreach处的诡异,推断最后一次foreach使$pushmsg的值为空了
  10. 考虑到这块代码比较底层,很少有人改。恰好昨天添加了一处isFromMiniProgram的判断,发现问题就出在这里
  11. isFromMiniProgram为真时返回了false,??语法糖操作符当前面是null时才会赋值其后面的值。所以当返回值是false时??并未起到赋值的作用,即最终$pushmsg == false

思考收获

  1. 之后如何避免类似隐性Bug的发生?
    1. 对核心基础功能引入单元测试,之后可以裹着发布系统玩
    2. code review升级。对于底层代码,实现者对review者讲解业务逻辑,及实现细节。review者逐行看代码
    3. 实现者必须写测试用例,哪怕很简单
  2. 排查bug的思考抓手
    1. 了解业务
    2. 查日志
    3. 缩小问题范围
  3. 有时候『笨』代码可能更可靠
    public static function sendTxtMsgToPatientByAuditor(Patient $patient, Auditor $auditor, $content, $appendarr = array()) {
        $wxusers = WxUserDao::getListByPatient($patient);
     
        $pushmsg = null;
        $appendarr[‘unitid‘] = Pipe::getUnitidMD5($patient->id);
        foreach ($wxusers as $wxuser) {
            $the_pushmsg = self::sendTxtMsgToWxUserByAuditor($wxuser, $auditor, $content, $appendarr);
            if ($the_pushmsg instanceof PushMsg) {
                $pushmsg = $the_pushmsg;
            }
        }
     
        return $pushmsg;
    }  
     
    public static function sendTxtMsgToPatientByAuditor(Patient $patient, Auditor $auditor, $content, $appendarr = array()) {
        $wxusers = WxUserDao::getListByPatient($patient);
     
        $pushmsg = null;
        $appendarr[‘unitid‘] = Pipe::getUnitidMD5($patient->id);
        foreach ($wxusers as $wxuser) {
            $pushmsg = self::sendTxtMsgToWxUserByAuditor($wxuser, $auditor, $content, $appendarr) ?? $pushmsg;
        }
     
        return $pushmsg;
    }

     

  4. ??操作符,当是null时才触发其后面的赋值操作。是false时不触发

基于Plan_txtMsg发消息bug复盘

原文:https://www.cnblogs.com/lxy1995/p/11393189.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!