向阳

两星期进去3次!只因为代码写成这样。。。

最近上线了一个新平台。问题不断,记录一下3次超发的问题
分析了一下代码。

活动逻辑

发放优惠券使用了支付1分钱认证卡种,如用户使用指定卡种支付后。给用户发放优惠券。认证失败后给用户退款。

事故一

起源

     ·由于A同事复制 上古代码
     
     事故分析:
      没有做预下单扣库存,支付回调时会写入一条领取成功记录。 下单时,会使用如下代码进行判断领取是否达到上限。
      由于支付是异步进行的,没有提前锁定库存。导致此代码在正常情况下都会超发。
   Integer receiveCount = itJcWxcardReceiveRelService.getReceiveCount(param.getStockId(), redisInfo.getUid(), WebUtils.getTisid());
            if (receiveCount >= couadvSetting.getBuylimitnum()) {
                //每日购买限制
                log.error("每日领取限制");
                throw new ShopAlertException(MsgEnums.DAY_OVERFLOW.getMsg());
            }

事故二

起源

    本次由B对本次活动优惠券下单认证逻辑添加了一层验证。
    逻辑如下 

image

    本来以为这样改了就没问题了。发到生产后,问题还是继续存在。代码如下:
  key = BaseConstant.RECEIVE_LIMIT_WEEK.concat(String.valueOf(tMiniTicketCouponInfo.getWxcardid()));
            Long sumCount = stringObjectRedisTemplate.boundValueOps(key).increment(1);
            stringObjectRedisTemplate.boundValueOps(key).expireAt(DateUtils.getEndDayOfWeek());
            if (sumCount > couadvSetting.getDaylimit()) {
                stringObjectRedisTemplate.boundValueOps(key).increment(-1);
                throw new ShopAlertException("本周领取数发放上限,请稍后再试");
            }

事故三

起源

    再次对代码进行分析,发现一个上古代码,取消库存逻辑如下:
          boolean update = tradeRecordWxService.update(new LambdaUpdateWrapper<TJcAppTradeRecordWx>()
                        .set(TJcAppTradeRecordWx::getTrstatus, "2")
                        .eq(TJcAppTradeRecordWx::getOrderid, orderid);
                if (update) {
                }
由于取消库存逻辑问题,存在重复取消订单的可能,且支付成功的订单也可能被修改为已取消。

修改上述问题后验证,发现回库存也存在问题 取消后本应该将tradeKey删除防止重复回库存,结果因为疏忽删错了key

导致整个库存校验逻辑失效。
      String tradeKey = BaseConstant.USER_RECEIVE_LIMIT_ORDER.concat(tradeRecordWx.getOrderid());
            String key = (String) stringObjectRedisTemplate.opsForValue().get(tradeKey);
            if (!com.shop.coupons.common.utils.StringUtils.isEmpty(key)){
                stringObjectRedisTemplate.boundValueOps(key).increment(-1);
                stringObjectRedisTemplate.delete(key);
            }
至此,以上问题都被修复。
总结:写代码需要严谨再严谨,由于之前验证过回库存逻辑,后期防止重复回库存,加了一个删除key的逻辑。没有验证就发布导致整个库存校验逻辑失效
Tags:

Blog with 向阳 [email protected]

粤ICP备2020128944号