qiurunze123/miaosha · error · GlobleException

30005

30005

Error message

Session不存在或者已经失效!

What it means

Thrown by GoodsController.detail2() (miaosha-v2) when the RPC call goodsServiceRpc.getGoodsVoByGoodsId(goodsId) returns a non-success result. Maps to ResultStatus.SESSION_ERROR (code 30005, 'Session不存在或者已经失效!'). This is a MISLABELED error: the failure is an RPC/data-fetch problem, not a session problem. The SESSION_ERROR code is misleading — it will confuse the front-end and debugging because it implies the user's session expired when in fact the goods provider failed. The provider's GoodsServiceImpl catches DB exceptions and returns ORDER_GET_FAIL (code 40004); the mock returns null which also triggers this path.

Source

Thrown at miaosha-v2/miaosha-web/src/main/java/com/geekq/miaosha/controller/GoodsController.java:91

    @RequestMapping(value = "/to_detail2/{goodsId}", produces = "text/html")
    @ResponseBody
    public String detail2(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user,
                          @PathVariable("goodsId") long goodsId) {
        model.addAttribute("user", user);

        //取缓存
        String html = redisService.get(GoodsKey.getGoodsDetail, "" + goodsId, String.class);
        if (!StringUtils.isEmpty(html)) {
            return html;
        }
        //手动渲染
        GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
        /**
         * rpc服务化接口
         */
        ResultGeekQOrder<GoodsVoOrder> goodsVoOrderResultGeekQOrder = goodsServiceRpc.getGoodsVoByGoodsId(goodsId);
        if (!AbstractResultOrder.isSuccess(goodsVoOrderResultGeekQOrder)) {
            throw new GlobleException(ResultStatus.SESSION_ERROR);
        }
        model.addAttribute("goods", goods);

        long startAt = goods.getStartDate().getTime();
        long endAt = goods.getEndDate().getTime();
        long now = System.currentTimeMillis();

        int miaoshaStatus = 0;
        int remainSeconds = 0;
        if (now < startAt) {//秒杀还没开始,倒计时
            miaoshaStatus = 0;
            remainSeconds = (int) ((startAt - now) / 1000);
        } else if (now > endAt) {//秒杀已经结束
            miaoshaStatus = 2;
            remainSeconds = -1;
        } else {//秒杀进行中
            miaoshaStatus = 1;
            remainSeconds = 0;

View on GitHub (pinned to e58017658e)

Solutions

  1. Replace ResultStatus.SESSION_ERROR with ResultStatus.SYSTEM_ERROR or a dedicated RPC error code to accurately reflect the failure cause.
  2. Verify miaosha-order-provider is running and registered in the service registry.
  3. Check provider logs for '获取单个订单失败' to find the underlying exception.
  4. Remove the redundant local goodsService.getGoodsVoByGoodsId() call (line 85) since the RPC result is what matters, or use the local result consistently.
  5. If the mock is active, fix GoodsServiceMock.getGoodsVoByGoodsId() to return a valid ResultGeekQOrder instead of null.

Example fix

// before
ResultGeekQOrder<GoodsVoOrder> goodsVoOrderResultGeekQOrder = goodsServiceRpc.getGoodsVoByGoodsId(goodsId);
if (!AbstractResultOrder.isSuccess(goodsVoOrderResultGeekQOrder)) {
    throw new GlobleException(ResultStatus.SESSION_ERROR);
}

// after — use the correct error code for an RPC failure
ResultGeekQOrder<GoodsVoOrder> goodsVoOrderResultGeekQOrder = goodsServiceRpc.getGoodsVoByGoodsId(goodsId);
if (!AbstractResultOrder.isSuccess(goodsVoOrderResultGeekQOrder)) {
    throw new GlobleException(ResultStatus.SYSTEM_ERROR);
}
Defensive patterns

Strategy: fallback

Validate before calling

// Use the local goodsService result that was already fetched at line 85
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
ResultGeekQOrder<GoodsVoOrder> rpcResult = goodsServiceRpc.getGoodsVoByGoodsId(goodsId);
if (!AbstractResultOrder.isSuccess(rpcResult)) {
    // Fall back to local result instead of throwing SESSION_ERROR
    if (goods == null) {
        throw new GlobleException(ResultStatus.SYSTEM_ERROR);
    }
    // proceed with local goods data
}

Type guard

// Validate RPC result before consuming
if (goodsVoOrderResultGeekQOrder != null
    && goodsVoOrderResultGeekQOrder.getStatus() == ResultStatusOrder.SUCCESS
    && goodsVoOrderResultGeekQOrder.getData() != null) {
    // safe to use goodsVoOrderResultGeekQOrder.getData()
}

Try / catch

try {
    ResultGeekQOrder<GoodsVoOrder> rpcResult = goodsServiceRpc.getGoodsVoByGoodsId(goodsId);
    if (!AbstractResultOrder.isSuccess(rpcResult)) {
        log.error("Goods RPC failed for goodsId={}", goodsId);
        throw new GlobleException(ResultStatus.SYSTEM_ERROR);
    }
} catch (GlobleException e) {
    // Do NOT treat as session error — it is an RPC failure
    throw e;
}

Prevention

When it happens

Trigger: GET /goods/to_detail2/{goodsId} when goodsServiceRpc.getGoodsVoByGoodsId() fails — provider DB error, provider down, or mock returning null. Note that detail2() also calls the local goodsService.getGoodsVoByGoodsId() at line 85 before the RPC check, so the local call may succeed while the RPC fails, leading to inconsistent behavior.

Common situations: miaosha-order-provider is down or deregistered from Dubbo; provider DB is unreachable; GoodsServiceMock is active (getGoodsVoByGoodsId returns null); provider times out; the goodsId does not exist in the provider's goods table (mapper returns null, which is set as data but status may not be SUCCESS depending on build()).

Related errors


AI-assisted analysis of qiurunze123/miaosha@e58017658e (2026-08-14). Data as JSON: /api/errors/320d9cf6d275cbd5. Report an issue: GitHub.