微信支付V3 消费后轮询支付结果的方案

1.场景

  1. 在支付中, 我们经常会遇到支付后, 支付结果没办法同步返回的情况, 也就是说用户已经支付了, 但是具体支付结果还需要等待一小段时间才能知道, 微信的支付有很多种, 小程序, app,公众号, 线下支付被扫, H5 等等, 有些支付是微信自动异常通知你的, 而有些支付是微信同步返回的, 但不是管是微信给你同步返回还是异步返回, 都会有可能存在延迟的情况, 那么我们就可以写一个轮询的机制, 只要用户支付了, 我们就去轮询的查询用户的支付结果, 并获取到支付状态,我们才好对交易做进一步的处理;
  2. 还有一种场景, 比较有针对性, 当我们开发的是付款码支付(线下商户支付被扫)的时候, 这个微信的接口如果是免密的情况会同步返回支付结果, 而当需要用户输入密码的情况返回的是一个202的http状态码, 这时候微信会去唤醒用户输入密码, 最终具体的支付结果微信并不会给你推送异步通知, 因为没有异步通知这个接口, 那么就需要你主动的去查询, 所以当微信返回202的时候,我们就可以在后台开启一个轮询的机制,去查询支付结果;

2.线程池选择

ScheduledExecutorService是延时执行的线程池,他可以用来代替timer定时器。
scheduleAtFixedRate()方法:

//循环执行任务,第一次执行时延时5秒后执行,然后第二次开始每间隔10秒执行一次,最后一个参数是时间单位
service.scheduleAtFixedRate(Runnable, 5, 10, TimeUnit.SECONDS);

大家有兴趣的可以去针对性的了了解下ScheduledExecutorService的使用,这里就不一一讲了;

3.核心线程数配置

  1. 轮询的时候线程经常需要挂起, 消耗的是cpu的资源, 上下文切换时间, 也就是说我们这个程序属于cpu密集型;
  2. 程序订单表记录的查询是根据唯一索引去查的, IO次数很少, 所以在IO上花费的时间并不多;
  3. 程序并发上比较稳定, 正常不会存在短时间内访问量激增的情况;
  4. 通过分析, 我们确定了目前的场景是: 并发不高, 执行时间长(这里的执行时间是线程挂起时间,所以消耗的是cpu的资源), 属于cpu密集型;
  5. 最后我们根据分析的场景把线程池的线程数设置为cpu核数+1, 线程不开太多, 减少线程上下文切换时间;

关于什么是IO密集型和CPU密集型,大家可以看下这篇文章:
https://blog.csdn.net/weixin_40151613/article/details/81835974

4.代码示例

//获取当前机器的核数
public static final int cpuNum = Runtime.getRuntime().availableProcessors();
    //轮询
    public void repeat(String tradeState, Map<String, Object> wechatinfo) {
        //延迟执行的线程池, 核心线程数以自己的服务器cpu去计算;
        ScheduledExecutorService service = newScheduledThreadPool(cpuNum+1);
        Map<String, String> queryReq = new HashMap<>();
        queryReq.put("outTradeNo", wechatinfo.get("out_trade_no"));
        queryReq.put("spmchid", wechatinfo.get("sp_mchid"));
        queryReq.put("submchid", wechatinfo.get("sub_chid"));
        //此方法无论执行时间长短,都是当一个任务执行完成之后,延退指定时间再开始执行第二个任务 
        service.scheduleAtFixedRate(new Runnable() {
            int count = 1;//计数器 count:初始为,Max=5;
            @Override
            public void run() {
                if (count < 6 && "USERPAYING".equals(tradeState)) {
                    //调用查询接口,新该订单状态(这部分是去调你的查询接口,大同小异自己修改一下)
                    log.info("queryorder 第" + count + "次轮询 start" + queryReq);
                    Commonresponse queryOrderResp = wechatTranInfo.queryOrder(queryReq);
                    log.info("queryorder 第" + count + "次轮询 end" + queryOrderResp);
                    Map<String, Object> queryResp = (Map) queryOrderResp.getResult();
                    String trade_state = StringUtil.nvl(queryResp.get("trade_state"));
                    count++;
                    //判断查询是否成功及订单状态是否USERPAYING,不为USERPAYING就去更新订单表;
                    if ("0".equals(queryOrderResp.getTransok()) && "IUSERPAYING".equals(trade_state)) {
                        Map<String, Object> map = fovaOrderInfo.updatebygtcg(queryResp);
                        log.info("支付更新订单表结果" + map);
                        service.shutdown();
                    }
                } else {
                    //超时撤单,(这部分是去调你的撤销订单接口,大同小异自己修改一下)
                    log.info("revokeorder超时撤单 start" + queryReq);
                    Commonresponse revokeResp = wechatTranVoid.revokeOrder(queryReq);
                    String trade_state = "0".equals(revokeResp.getTransok()) ? "REVOKED" : "NREVOKED";
                    //更新订单表入参
                    HashMap<String, Object> revokeOrderIntput = new HashMap<>();
                    //新增类型,撤销
                    revokeOrderIntput.put("trade_ state", trade_state);//设置订单状态
                    revokeOrderIntput.put("out trade_no", wechatinfo.get("out_trade_no"));//设置商户订单号
                    Map<String, Object> map = fovaorderinfo.updateByGtcg(revokeOrderIntput);//更新订单表
                    log.info("撤单更新订单表结果" + map);
                    service.shutdown();
                }
            }
        }, 5, 10, TimeUnit.NANOSECONDS);
    }

今天的分享就到这里,有什么微信疑问的可以联系我 WX: yufei4358

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾轻鸿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值