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

2. 修复定时任务的回调,回调成功未更新状态的问题。
This commit is contained in:
YunaiV 2023-02-16 23:54:23 +08:00
parent 44b0346e5e
commit 96ecd5028d
5 changed files with 21 additions and 19 deletions

View File

@ -48,7 +48,7 @@ public class PayDemoOrderController {
} }
@PostMapping("/update-paid") @PostMapping("/update-paid")
@Operation(description = "更新示例订单为已支付") // pay-module 支付服务进行回调可见 PayNotifyJob @Operation(summary = "更新示例订单为已支付") // pay-module 支付服务进行回调可见 PayNotifyJob
@PermitAll // 无需登录安全由 PayDemoOrderService 内部校验实现 @PermitAll // 无需登录安全由 PayDemoOrderService 内部校验实现
@OperateLog(enable = false) // 禁用操作日志因为没有操作人 @OperateLog(enable = false) // 禁用操作日志因为没有操作人
public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { public CommonResult<Boolean> updateDemoOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
@ -58,7 +58,7 @@ public class PayDemoOrderController {
} }
@PutMapping("/refund") @PutMapping("/refund")
@Operation(description = "发起示例订单的退款") @Operation(summary = "发起示例订单的退款")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) { public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) {
payDemoOrderService.refundDemoOrder(id, getClientIP()); payDemoOrderService.refundDemoOrder(id, getClientIP());
@ -66,7 +66,7 @@ public class PayDemoOrderController {
} }
@PostMapping("/update-refunded") @PostMapping("/update-refunded")
@Operation(description = "更新示例订单为已退款") // pay-module 支付服务进行回调可见 PayNotifyJob @Operation(summary = "更新示例订单为已退款") // pay-module 支付服务进行回调可见 PayNotifyJob
@PermitAll // 无需登录安全由 PayDemoOrderService 内部校验实现 @PermitAll // 无需登录安全由 PayDemoOrderService 内部校验实现
@OperateLog(enable = false) // 禁用操作日志因为没有操作人 @OperateLog(enable = false) // 禁用操作日志因为没有操作人
public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) { public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {

View File

@ -5,5 +5,5 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface PayNotifyLogCoreMapper extends BaseMapperX<PayNotifyLogDO> { public interface PayNotifyLogMapper extends BaseMapperX<PayNotifyLogDO> {
} }

View File

@ -10,7 +10,7 @@ import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface PayNotifyTaskCoreMapper extends BaseMapperX<PayNotifyTaskDO> { public interface PayNotifyTaskMapper extends BaseMapperX<PayNotifyTaskDO> {
/** /**
* 获得需要通知的 PayNotifyTaskDO 记录需要满足如下条件 * 获得需要通知的 PayNotifyTaskDO 记录需要满足如下条件

View File

@ -13,8 +13,8 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogCoreMapper; import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskCoreMapper; import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper;
import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
@ -32,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -40,6 +41,7 @@ import java.util.Objects;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
import static cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration.NOTIFY_THREAD_POOL_TASK_EXECUTOR; import static cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration.NOTIFY_THREAD_POOL_TASK_EXECUTOR;
/** /**
@ -69,9 +71,9 @@ public class PayNotifyServiceImpl implements PayNotifyService {
private PayRefundService refundService; private PayRefundService refundService;
@Resource @Resource
private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper; private PayNotifyTaskMapper payNotifyTaskMapper;
@Resource @Resource
private PayNotifyLogCoreMapper payNotifyLogCoreMapper; private PayNotifyLogMapper payNotifyLogMapper;
@Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR) @Resource(name = NOTIFY_THREAD_POOL_TASK_EXECUTOR)
private ThreadPoolTaskExecutor threadPoolTaskExecutor; private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@ -101,7 +103,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
} }
// 执行插入 // 执行插入
payNotifyTaskCoreMapper.insert(task); payNotifyTaskMapper.insert(task);
// 异步直接发起任务虽然会有定时任务扫描但是会导致延迟 // 异步直接发起任务虽然会有定时任务扫描但是会导致延迟
self.executeNotifyAsync(task); self.executeNotifyAsync(task);
@ -110,7 +112,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
@Override @Override
public int executeNotify() throws InterruptedException { public int executeNotify() throws InterruptedException {
// 获得需要通知的任务 // 获得需要通知的任务
List<PayNotifyTaskDO> tasks = payNotifyTaskCoreMapper.selectListByNotify(); List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify();
if (CollUtil.isEmpty(tasks)) { if (CollUtil.isEmpty(tasks)) {
return 0; return 0;
} }
@ -168,8 +170,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
// 校验当前任务是否已经被通知过 // 校验当前任务是否已经被通知过
// 虽然已经通过分布式加锁但是可能同时满足通知的条件然后都去获得锁此时第一个执行完后第二个还是能拿到锁然后会再执行一次 // 虽然已经通过分布式加锁但是可能同时满足通知的条件然后都去获得锁此时第一个执行完后第二个还是能拿到锁然后会再执行一次
PayNotifyTaskDO dbTask = payNotifyTaskCoreMapper.selectById(task.getId()); PayNotifyTaskDO dbTask = payNotifyTaskMapper.selectById(task.getId());
if (LocalDateTimeUtils.afterNow(dbTask.getNextNotifyTime())) { if (afterNow(dbTask.getNextNotifyTime())) {
log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]",
JsonUtils.toJsonString(dbTask)); JsonUtils.toJsonString(dbTask));
return; return;
@ -197,7 +199,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
// 记录 PayNotifyLog 日志 // 记录 PayNotifyLog 日志
String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) :
JsonUtils.toJsonString(invokeResult); JsonUtils.toJsonString(invokeResult);
payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) payNotifyLogMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
.notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
} }
@ -250,23 +252,22 @@ public class PayNotifyServiceImpl implements PayNotifyService {
// 情况一调用成功 // 情况一调用成功
if (invokeResult != null && invokeResult.isSuccess()) { if (invokeResult != null && invokeResult.isSuccess()) {
updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
payNotifyTaskMapper.updateById(updateTask);
return updateTask.getStatus(); return updateTask.getStatus();
} }
// 情况二调用失败调用异常 // 情况二调用失败调用异常
// 2.1 超过最大回调次数 // 2.1 超过最大回调次数
if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
payNotifyTaskMapper.updateById(updateTask);
return updateTask.getStatus(); return updateTask.getStatus();
} }
// 2.2 未超过最大回调次数 // 2.2 未超过最大回调次数
updateTask.setNextNotifyTime(LocalDateTime.now().plusSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])); updateTask.setNextNotifyTime(addTime(Duration.ofSeconds(PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])));
updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
: PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
payNotifyTaskMapper.updateById(updateTask);
return updateTask.getStatus(); return updateTask.getStatus();
} }
private void processNotifySuccess(PayNotifyTaskDO task, PayNotifyTaskDO updateTask) {
payNotifyTaskCoreMapper.updateById(updateTask);
}
} }

View File

@ -153,6 +153,7 @@ logging:
cn.iocoder.yudao.module.infra.dal.mysql: debug cn.iocoder.yudao.module.infra.dal.mysql: debug
cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info
cn.iocoder.yudao.module.pay.dal.mysql: debug cn.iocoder.yudao.module.pay.dal.mysql: debug
cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 JobLogMapper 的日志级别为 info
cn.iocoder.yudao.module.system.dal.mysql: debug cn.iocoder.yudao.module.system.dal.mysql: debug
cn.iocoder.yudao.module.tool.dal.mysql: debug cn.iocoder.yudao.module.tool.dal.mysql: debug
cn.iocoder.yudao.module.member.dal.mysql: debug cn.iocoder.yudao.module.member.dal.mysql: debug