订单支付异常情况处理

简介: 订单支付异常情况处理

正常情况下我们选择商品然后购买,完成支付后就发货了,但是因为大多采用的是http协议,如果出现了网络异常等情况就会掉单之类的,比如顾客付完钱了但是订单状态并没有改变,还有就是支付成功后回调失败,导致没有发货。对于真正的服务,这些异常情况我们也得考虑进去。

上面基本就是订单服务的主流程了,但是我们可以思考一下异常流程:

  1. 用户订单创建成功,但创建支付单 HTTP 超时失败。
  2. 支付回调时,系统宕机或者本身服务出问题。
  3. 支付成功后发送MQ消息,消息丢失,用户支付掉单。
  4. 长时间未支付,超时订单。

那么,这些就都是可能出现的异常流程。虽然概率很低,但随着使用规模的增加,很低概率的问题,也会产生较大规模的客诉问题。所以要针对这些流程做补偿处理。

  1. 针对1~4提到异常流程,一条支付链路就会被扩展为现在的样子,在各个流程中需要穿插进入异常补偿流程。
  2. 用户下单,但可能存在之前下的残单,那么就要对应给予补充的流程后,再返回回去。
  3. 支付回调,仍然可能有异常。所以要有掉单补偿和发货补偿。两条任务处理。

 

因此,我们通过使用定时任务完成补偿

1. 掉单补偿,检测未接收到或未正确处理的支付回调通知(即用户已经扫码支付成功但是订单状态没有改变)

@Component
@Slf4j
public class NoPayNotifyOrderJob {
 
    @Resource
    private IOrderRepository orderRepository;
 
    @Resource
    private IOrderService orderService;
 
    @Resource
    private RabbitTemplate rabbitTemplate;
 
 
    @Value("${pay.alipay.APP_ID}")
    private String APP_ID;
 
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    private String APP_PRIVATE_KEY;
 
    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    private String ALIPAY_PUBLIC_KEY;
 
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
 
    @Timed(value = "no_pay_notify_order_job", description = "定时任务,订单支付状态更新")
    @Scheduled(cron = "0/3 * * * * ?")
    public void exec(){
        try {
            List<String> orderIds = orderRepository.queryNoPayNotifyOrder();
            if (orderIds.isEmpty()) {
                log.info("定时任务,订单支付状态更新,暂无未更新订单 orderId is null");
                return;
            }
 
            for (String orderId: orderIds) {
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,
                        APP_ID,
                        APP_PRIVATE_KEY,
                        AlipayConfig.FORMAT,
                        AlipayConfig.CHARSET,
                        ALIPAY_PUBLIC_KEY,
                        AlipayConfig.SIGNTYPE);
 
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                JSONObject bizContent = new JSONObject();
                bizContent.put("out_trade_no", orderId);
                request.setBizContent(bizContent.toString());
                AlipayTradeQueryResponse response = null;
                try {
                    response = alipayClient.execute(request);
                    if (!response.isSuccess()) {
                        new ChatGPTException("请求支付查询查询失败");
                    }
                } catch (AlipayApiException e) {
                    log.error("请求支付宝查询支付结果异常:{}", e.toString(), e);
                    new ChatGPTException("请求支付查询查询失败");
                }
 
                //获取支付结果
                String resultJson = response.getBody();
                //转map
                Map resultMap = JSON.parseObject(resultJson, Map.class);
                Map alipay_trade_query_response = (Map) resultMap.get("alipay_trade_query_response");
                //支付结果
                Double total_amount = Double.valueOf(alipay_trade_query_response.get("total_amount").toString());
                String trade_no = (String) alipay_trade_query_response.get("trade_no");
                String successTime = (String)alipay_trade_query_response.get("gmt_payment");
 
                boolean isSuccess = orderService.changeOrderPaySuccess(orderId, trade_no, BigDecimal.valueOf(total_amount), dateFormat.parse(successTime));
 
                if (isSuccess) {
                    // 发布消息
                    rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"", orderId);
                }
            }
        }catch (Exception e){
            log.error("定时任务,订单支付状态更新失败", e);
            e.printStackTrace();
        }
    }
 
}

2.订单补货任务

@Component
@Slf4j
public class OrderReplenishmentJob {
 
    @Resource
    private IOrderService orderService;
 
    @Resource
    private RabbitTemplate rabbitTemplate;
 
 
    /**
     * 执行订单补货,超时3分钟,已支付,待发货未发货的订单
     */
    @Scheduled(cron = "0 0/3 * * * ?")
    public void exec() {
        try {
            List<String> orderIds = orderService.queryReplenishmentOrder();
            if (orderIds.isEmpty()) {
                log.info("定时任务,订单补货不存在,查询 orderIds is null");
                return;
            }
            for (String orderId : orderIds) {
                log.info("定时任务,订单补货开始。orderId: {}", orderId);
                rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"", orderId);
            }
        } catch (Exception e) {
            log.error("定时任务,订单补货失败。", e);
        }
    }
}

3. 超时关单任务

@Component
@Slf4j
public class TimeoutCloseOrderJob {
 
    @Resource
    private IOrderService orderService;
 
    @Scheduled(cron = "0 0/30 * * * ?")
    public void exec() {
       try {
           List<String> orderIds = orderService.queryTimeoutCloseOrderList();
           for (String orderId: orderIds) {
               boolean status = orderService.changeOrderClose(orderId);
               log.info("定时任务,超时30分钟订单关闭 orderId: {} status:{}", orderId, status);
           }
       }catch (Exception e) {
           log.error("定时任务,超时15分钟订单关闭失败", e);
       }
    }
}


目录
相关文章
|
机器学习/深度学习
集合论—笛卡尔积与二元关系
集合论—笛卡尔积与二元关系
|
10月前
|
安全
移动硬盘提示需要格式化怎么办?这样操作数据还能保住!
当移动硬盘提示“需要格式化”时,很多人会误操作导致数据丢失。本文详解了硬盘提示格式化的常见原因,并提供不格式化恢复数据的具体方法,包括使用DiskGenius直接读取、智能加载分区和深度扫描等步骤。同时介绍了修复硬盘及预防问题的实用技巧,帮助你安全应对突发情况,保护重要数据。
|
设计模式 前端开发 JavaScript
自动化测试框架设计原则与最佳实践####
本文深入探讨了构建高效、可维护的自动化测试框架的核心原则与策略,旨在为软件测试工程师提供一套系统性的方法指南。通过分析常见误区,结合行业案例,阐述了如何根据项目特性定制自动化策略,优化测试流程,提升测试覆盖率与执行效率。 ####
516 6
|
12月前
|
机器学习/深度学习 人工智能 运维
AI加持的系统性能优化:别让你的服务器“累趴下”
AI加持的系统性能优化:别让你的服务器“累趴下”
606 12
|
安全 网络安全
网络安全攻防实战演练:技术探索与实践
【5月更文挑战第1天】网络安全攻防实战演练,通过模拟攻击与防御,提升组织应对网络安全威胁的能力。演练包括准备、攻击、防御和总结四个阶段,涉及环境搭建、攻击技术应用、防御措施执行及后期评估。此类演练有助于检验安全防护能力,提升应急响应速度,暴露系统隐患,加强团队协作,是保障网络安全的关键实践。
|
存储 人工智能 JSON
RAG Logger:专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、性能监控
RAG Logger 是一款专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、检索结果记录、LLM 交互记录和性能监控等功能。
665 7
RAG Logger:专为检索增强生成(RAG)应用设计的开源日志工具,支持查询跟踪、性能监控
|
人工智能 自然语言处理 监控
《AI赋能共享经济:资源配置与服务质量的双重优化》
共享经济借助互联网平台实现闲置资源高效利用,AI技术的融入进一步优化资源配置和服务质量。AI通过精准需求预测、智能调度和动态分配策略提升资源使用效率;借助个性化推荐、智能客服和实时监控改善用户体验。典型案例如Airbnb和滴滴出行展示了AI在提高预订率、减少等待时间和提升安全方面的显著成效。尽管面临数据隐私等挑战,AI仍为共享经济带来巨大创新和发展机遇。
728 18
|
安全 网络安全 网络虚拟化
配置分支机构与总部之间通过L2TP Over IPSec方式实现安全互通
本文介绍了如何通过配置L2TP over IPSec实现企业分支与总部之间的安全通信。AR1作为分支网关,AR3作为总部网关,通过自拨号方式建立L2TP隧道,并使用IPSec加密保护数据传输,防止信息被窃取或篡改。主要步骤包括配置接口IP地址和静态路由、设置L2TP功能、定义ACL、创建IPSec安全提议、配置IKE对等体、制定安全策略并应用到接口上。最终验证了配置成功后,PC1能够顺利ping通PC2,确保了网络互通和数据安全。
|
人工智能 运维 Kubernetes
拥抱智算时代:阿里云容器服务智能、托管、弹性新体验
本文总结了2024云栖大会容器计算专场的演讲内容,重点介绍了阿里云容器服务的新产品体验,包括智能、托管、弹性的特点,以及如何助力客户拥抱智算时代。文中还分享了多项实际案例和技术细节,展示了阿里云容器服务在提升用户体验和解决实际问题方面的努力。