Commit 96ecd5028dbf46e48cbb18bc61ae8ef40ba720c3

Authored by YunaiV
1 parent 44b0346e

1. 优化支付订单回调任务,避免重复打 SQL 查询日志

2. 修复定时任务的回调,回调成功未更新状态的问题。
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java
@@ -48,7 +48,7 @@ public class PayDemoOrderController { @@ -48,7 +48,7 @@ public class PayDemoOrderController {
48 } 48 }
49 49
50 @PostMapping("/update-paid") 50 @PostMapping("/update-paid")
51 - @Operation(description = "更新示例订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob 51 + @Operation(summary = "更新示例订单为已支付") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
52 @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 52 @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
53 @OperateLog(enable = false) // 禁用操作日志,因为没有操作人 53 @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
54 public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { 54 public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
@@ -58,7 +58,7 @@ public class PayDemoOrderController { @@ -58,7 +58,7 @@ public class PayDemoOrderController {
58 } 58 }
59 59
60 @PutMapping("/refund") 60 @PutMapping("/refund")
61 - @Operation(description = "发起示例订单的退款") 61 + @Operation(summary = "发起示例订单的退款")
62 @Parameter(name = "id", description = "编号", required = true, example = "1024") 62 @Parameter(name = "id", description = "编号", required = true, example = "1024")
63 public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) { 63 public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) {
64 payDemoOrderService.refundDemoOrder(id, getClientIP()); 64 payDemoOrderService.refundDemoOrder(id, getClientIP());
@@ -66,7 +66,7 @@ public class PayDemoOrderController { @@ -66,7 +66,7 @@ public class PayDemoOrderController {
66 } 66 }
67 67
68 @PostMapping("/update-refunded") 68 @PostMapping("/update-refunded")
69 - @Operation(description = "更新示例订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob 69 + @Operation(summary = "更新示例订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
70 @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 70 @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
71 @OperateLog(enable = false) // 禁用操作日志,因为没有操作人 71 @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
72 public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { 72 public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogCoreMapper.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyLogMapper.java
@@ -5,5 +5,5 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; @@ -5,5 +5,5 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import org.apache.ibatis.annotations.Mapper; 5 import org.apache.ibatis.annotations.Mapper;
6 6
7 @Mapper 7 @Mapper
8 -public interface PayNotifyLogCoreMapper extends BaseMapperX<PayNotifyLogDO> { 8 +public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> {
9 } 9 }
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskCoreMapper.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/notify/PayNotifyTaskMapper.java
@@ -10,7 +10,7 @@ import java.time.LocalDateTime; @@ -10,7 +10,7 @@ import java.time.LocalDateTime;
10 import java.util.List; 10 import java.util.List;
11 11
12 @Mapper 12 @Mapper
13 -public interface PayNotifyTaskCoreMapper extends BaseMapperX<PayNotifyTaskDO> { 13 +public interface PayNotifyTaskMapper extends BaseMapperX<PayNotifyTaskDO> {
14 14
15 /** 15 /**
16 * 获得需要通知的 PayNotifyTaskDO 记录。需要满足如下条件: 16 * 获得需要通知的 PayNotifyTaskDO 记录。需要满足如下条件:
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
@@ -13,8 +13,8 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; @@ -13,8 +13,8 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
13 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; 13 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
14 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 14 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
15 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 15 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
16 -import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogCoreMapper;  
17 -import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskCoreMapper; 16 +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper;
  17 +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper;
18 import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; 18 import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
19 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; 19 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
20 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 20 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
@@ -32,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional; @@ -32,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
32 32
33 import javax.annotation.Resource; 33 import javax.annotation.Resource;
34 import javax.validation.Valid; 34 import javax.validation.Valid;
  35 +import java.time.Duration;
35 import java.time.LocalDateTime; 36 import java.time.LocalDateTime;
36 import java.util.HashMap; 37 import java.util.HashMap;
37 import java.util.List; 38 import java.util.List;
@@ -40,6 +41,7 @@ import java.util.Objects; @@ -40,6 +41,7 @@ import java.util.Objects;
40 import java.util.concurrent.CountDownLatch; 41 import java.util.concurrent.CountDownLatch;
41 import java.util.concurrent.TimeUnit; 42 import java.util.concurrent.TimeUnit;
42 43
  44 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
43 import static cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration.NOTIFY_THREAD_POOL_TASK_EXECUTOR; 45 import static cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration.NOTIFY_THREAD_POOL_TASK_EXECUTOR;
44 46
45 /** 47 /**
@@ -69,9 +71,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -69,9 +71,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
69 private PayRefundService refundService; 71 private PayRefundService refundService;
70 72
71 @Resource 73 @Resource
72 - private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper; 74 + private PayNotifyTaskMapper payNotifyTaskMapper;
73 @Resource 75 @Resource
74 - private PayNotifyLogCoreMapper payNotifyLogCoreMapper; 76 + private PayNotifyLogMapper payNotifyLogMapper;
75 77
76 @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR) 78 @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR)
77 private ThreadPoolTaskExecutor threadPoolTaskExecutor; 79 private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@@ -101,7 +103,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -101,7 +103,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
101 } 103 }
102 104
103 // 执行插入 105 // 执行插入
104 - payNotifyTaskCoreMapper.insert(task); 106 + payNotifyTaskMapper.insert(task);
105 107
106 // 异步直接发起任务。虽然会有定时任务扫描,但是会导致延迟 108 // 异步直接发起任务。虽然会有定时任务扫描,但是会导致延迟
107 self.executeNotifyAsync(task); 109 self.executeNotifyAsync(task);
@@ -110,7 +112,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -110,7 +112,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
110 @Override 112 @Override
111 public int executeNotify() throws InterruptedException { 113 public int executeNotify() throws InterruptedException {
112 // 获得需要通知的任务 114 // 获得需要通知的任务
113 - List<PayNotifyTaskDO> tasks = payNotifyTaskCoreMapper.selectListByNotify(); 115 + List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify();
114 if (CollUtil.isEmpty(tasks)) { 116 if (CollUtil.isEmpty(tasks)) {
115 return 0; 117 return 0;
116 } 118 }
@@ -168,8 +170,8 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -168,8 +170,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
168 payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { 170 payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
169 // 校验,当前任务是否已经被通知过 171 // 校验,当前任务是否已经被通知过
170 // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。 172 // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。
171 - PayNotifyTaskDO dbTask = payNotifyTaskCoreMapper.selectById(task.getId());  
172 - if (LocalDateTimeUtils.afterNow(dbTask.getNextNotifyTime())) { 173 + PayNotifyTaskDO dbTask = payNotifyTaskMapper.selectById(task.getId());
  174 + if (afterNow(dbTask.getNextNotifyTime())) {
173 log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", 175 log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]",
174 JsonUtils.toJsonString(dbTask)); 176 JsonUtils.toJsonString(dbTask));
175 return; 177 return;
@@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
197 // 记录 PayNotifyLog 日志 199 // 记录 PayNotifyLog 日志
198 String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : 200 String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
199 JsonUtils.toJsonString(invokeResult); 201 JsonUtils.toJsonString(invokeResult);
200 - payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) 202 + payNotifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
201 .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); 203 .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
202 } 204 }
203 205
@@ -250,23 +252,22 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -250,23 +252,22 @@ public class PayNotifyServiceImpl implements PayNotifyService {
250 // 情况一:调用成功 252 // 情况一:调用成功
251 if (invokeResult != null && invokeResult.isSuccess()) { 253 if (invokeResult != null && invokeResult.isSuccess()) {
252 updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); 254 updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
  255 + payNotifyTaskMapper.updateById(updateTask);
253 return updateTask.getStatus(); 256 return updateTask.getStatus();
254 } 257 }
255 // 情况二:调用失败、调用异常 258 // 情况二:调用失败、调用异常
256 // 2.1 超过最大回调次数 259 // 2.1 超过最大回调次数
257 if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { 260 if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
258 updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); 261 updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
  262 + payNotifyTaskMapper.updateById(updateTask);
259 return updateTask.getStatus(); 263 return updateTask.getStatus();
260 } 264 }
261 // 2.2 未超过最大回调次数 265 // 2.2 未超过最大回调次数
262 - updateTask.setNextNotifyTime(LocalDateTime.now().plusSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])); 266 + updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])));
263 updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() 267 updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
264 : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); 268 : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
  269 + payNotifyTaskMapper.updateById(updateTask);
265 return updateTask.getStatus(); 270 return updateTask.getStatus();
266 } 271 }
267 272
268 - private void processNotifySuccess(PayNotifyTaskDO task, PayNotifyTaskDO updateTask) {  
269 - payNotifyTaskCoreMapper.updateById(updateTask);  
270 - }  
271 -  
272 } 273 }
yudao-server/src/main/resources/application-local.yaml
@@ -153,6 +153,7 @@ logging: @@ -153,6 +153,7 @@ logging:
153 cn.iocoder.yudao.module.infra.dal.mysql: debug 153 cn.iocoder.yudao.module.infra.dal.mysql: debug
154 cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info 154 cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info
155 cn.iocoder.yudao.module.pay.dal.mysql: debug 155 cn.iocoder.yudao.module.pay.dal.mysql: debug
  156 + cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 JobLogMapper 的日志级别为 info
156 cn.iocoder.yudao.module.system.dal.mysql: debug 157 cn.iocoder.yudao.module.system.dal.mysql: debug
157 cn.iocoder.yudao.module.tool.dal.mysql: debug 158 cn.iocoder.yudao.module.tool.dal.mysql: debug
158 cn.iocoder.yudao.module.member.dal.mysql: debug 159 cn.iocoder.yudao.module.member.dal.mysql: debug