From 04538cc1414b4dde5079a5f183e33d08ad108917 Mon Sep 17 00:00:00 2001
From: nws <3239709711@qq.com>
Date: Sat, 6 Jan 2024 18:35:20 +0800
Subject: [PATCH] =?UTF-8?q?feat=20=E8=AE=A2=E5=8D=95=E5=8F=96=E6=B6=88/?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D/=E5=8F=96=E6=B6=88/=E5=90=8C=E6=AD=A5?=
=?UTF-8?q?=E7=AD=89=E6=93=8D=E4=BD=9C=E6=B7=BB=E5=8A=A0=E5=88=86=E5=B8=83?=
=?UTF-8?q?=E5=BC=8F=E9=94=81,=20=E9=98=B2=E6=AD=A2=E5=87=BA=E7=8E=B0?=
=?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
_doc/Task.md | 6 +-
daxpay-single/daxpay-single-admin/pom.xml | 2 +-
daxpay-single/daxpay-single-service/pom.xml | 10 +--
.../close/service/PayCloseService.java | 15 +++-
.../core/payment/pay/service/PayService.java | 47 ++++++----
.../refund/service/PayRefundService.java | 42 ++++++---
.../payment/sync/service/PaySyncService.java | 87 +++++++++++--------
.../sync/task/PayOrderSyncTaskService.java | 39 ---------
.../core/timeout/task/PayExpiredTimeTask.java | 16 +++-
.../timeout/task/PayWaitOrderSyncTask.java | 13 ++-
pom.xml | 2 +-
11 files changed, 161 insertions(+), 118 deletions(-)
delete mode 100644 daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/task/PayOrderSyncTaskService.java
diff --git a/_doc/Task.md b/_doc/Task.md
index 46909ae59..a315f4a3a 100644
--- a/_doc/Task.md
+++ b/_doc/Task.md
@@ -28,19 +28,17 @@
- 2024-01-05:
- [x] 支付同步日志记录, 无论同步成功还是失败, 以及修复成功还是失败, 都需要记录日志
- [x] 超时自动取消功能联调, 先用spring定时任务实现, 通过支付同步实现
+ - [x] 支付同步和修复时, 对一些模糊状态进行处理, 例如支付宝返回的订单未查到
- [x] 待支付支付单定时同步状态, 先用spring定时任务实现, 通过支付同步实现
- [x] 退款功能联调
- 2024-01-06:
+ - [x] 订单取消/修复/取消/同步等操作添加分布式锁, 防止出现重复操作
- [ ] 增加支付修复记录
- [ ] 退款状态同步逻辑
- [ ] 退款回调的处理
- [ ] 支付状态同步处理考虑退款情况
- [ ] 增加消息通知机制(通知客户端)
- **任务池**
- - 支付同步时,有些状态无法区分处理, 导致无法修复
- - 下面内容同: 支付网关/本地
- - 支付宝: 订单未找到/支付关闭 支付网关/支付超时 支付网关/支付成功
- - 订单取消/修复/取消/同步添加分布式锁, 防止操作订单时出现重复操作
- 支付状态同步处理退款情况
- 支付配置支持数据库配置和配置文件配置
- 增加回调机制(通知客户端)
diff --git a/daxpay-single/daxpay-single-admin/pom.xml b/daxpay-single/daxpay-single-admin/pom.xml
index af190e449..02d5a3a57 100644
--- a/daxpay-single/daxpay-single-admin/pom.xml
+++ b/daxpay-single/daxpay-single-admin/pom.xml
@@ -25,7 +25,7 @@
${bootx-platform.version}
-
+
com.baomidou
lock4j-redis-template-spring-boot-starter
diff --git a/daxpay-single/daxpay-single-service/pom.xml b/daxpay-single/daxpay-single-service/pom.xml
index 6e162683b..291008862 100644
--- a/daxpay-single/daxpay-single-service/pom.xml
+++ b/daxpay-single/daxpay-single-service/pom.xml
@@ -56,11 +56,6 @@
common-super-query
-
- org.redisson
- redisson-spring-boot-starter
-
-
cn.bootx.platform
@@ -104,5 +99,10 @@
junit-jupiter
test
+
+ com.baomidou
+ lock4j-redis-template-spring-boot-starter
+ ${lock4j.version}
+
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/service/PayCloseService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/service/PayCloseService.java
index 33e1ebafe..4585c9d63 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/service/PayCloseService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/service/PayCloseService.java
@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.service.core.payment.close.service;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
@@ -13,6 +14,8 @@ import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy;
import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -34,6 +37,8 @@ public class PayCloseService {
private final PayOrderService payOrderService;
private final PayCloseRecordService payCloseRecordService;
+ private final LockTemplate lockTemplate;
+
/**
* 关闭支付
*/
@@ -48,7 +53,15 @@ public class PayCloseService {
payOrder = payOrderService.findByBusinessNo(param.getBusinessNo())
.orElseThrow(() -> new PayFailureException("未查询到支付订单"));
}
- this.close(payOrder);
+ LockInfo lock = lockTemplate.lock("payment:close:" + payOrder.getId());
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("支付订单已在关闭中,请勿重复发起");
+ }
+ try {
+ this.close(payOrder);
+ } finally {
+ lockTemplate.releaseLock(lock);
+ }
}
/**
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java
index 398e7248f..063e3745b 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/service/PayService.java
@@ -1,21 +1,24 @@
package cn.bootx.platform.daxpay.service.core.payment.pay.service;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
-import cn.bootx.platform.daxpay.service.core.payment.pay.factory.PayStrategyFactory;
-import cn.bootx.platform.daxpay.service.core.record.pay.builder.PaymentBuilder;
-import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
-import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException;
-import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
-import cn.bootx.platform.daxpay.service.func.PayStrategyConsumer;
import cn.bootx.platform.daxpay.param.pay.PayParam;
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
import cn.bootx.platform.daxpay.param.pay.SimplePayParam;
import cn.bootx.platform.daxpay.result.pay.PayResult;
+import cn.bootx.platform.daxpay.service.core.payment.pay.factory.PayStrategyFactory;
+import cn.bootx.platform.daxpay.service.core.record.pay.builder.PaymentBuilder;
+import cn.bootx.platform.daxpay.service.core.record.pay.entity.PayOrder;
+import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
+import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
+import cn.bootx.platform.daxpay.service.func.PayStrategyConsumer;
import cn.bootx.platform.daxpay.util.PayUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -41,6 +44,8 @@ public class PayService {
private final PayAssistService payAssistService;
+ private final LockTemplate lockTemplate;
+
/**
* 支付下单接口(同步/异步/组合支付)
* 1. 同步支付:都只会在第一次执行中就完成支付,例如钱包、储值卡都是调用完就进行了扣减,完成了支付记录
@@ -55,18 +60,28 @@ public class PayService {
// 异步支付方式检查
PayUtil.validationAsyncPay(payParam);
- // 获取并校验支付订单状态, 如果超时, 触发支付单同步和修复动作
- PayOrder payOrder = payAssistService.getOrderAndCheck(payParam.getBusinessNo());
+ String businessNo = payParam.getBusinessNo();
+ // 加锁
+ LockInfo lock = lockTemplate.lock("payment:pay:" + businessNo);
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("正在支付中,请勿重复支付");
+ }
+ try {
+ // 获取并校验支付订单状态, 如果超时, 触发支付单同步和修复动作
+ PayOrder payOrder = payAssistService.getOrderAndCheck(payParam.getBusinessNo());
- // 初始化上下文
- payAssistService.initPayContext(payOrder, payParam);
+ // 初始化上下文
+ payAssistService.initPayContext(payOrder, payParam);
- // 异步支付且非第一次支付
- if (Objects.nonNull(payOrder) && payOrder.isAsyncPay()) {
- return this.paySyncNotFirst(payParam, payOrder);
- } else {
- // 第一次发起支付或同步支付
- return this.firstPay(payParam, payOrder);
+ // 异步支付且非第一次支付
+ if (Objects.nonNull(payOrder) && payOrder.isAsyncPay()) {
+ return this.paySyncNotFirst(payParam, payOrder);
+ } else {
+ // 第一次发起支付或同步支付
+ return this.firstPay(payParam, payOrder);
+ }
+ } finally {
+ lockTemplate.releaseLock(lock);
}
}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/service/PayRefundService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/service/PayRefundService.java
index 2a8629895..3e171760a 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/service/PayRefundService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/service/PayRefundService.java
@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.service.core.payment.refund.service;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.service.core.payment.refund.factory.PayRefundStrategyFactory;
@@ -13,6 +14,8 @@ import cn.bootx.platform.daxpay.param.pay.SimpleRefundParam;
import cn.bootx.platform.daxpay.result.pay.RefundResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -20,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -35,6 +39,9 @@ public class PayRefundService {
private final PayRefundAssistService payRefundAssistService;;
private final PayOrderService payOrderService;
+
+ private final LockTemplate lockTemplate;
+
/**
* 支付退款
*/
@@ -69,19 +76,30 @@ public class PayRefundService {
PayOrder payOrder = payRefundAssistService.getPayOrderAndCheckByRefundParam(param, simple);
// 参数校验
ValidationUtil.validateParam(param);
- // 退款上下文初始化
- payRefundAssistService.initRefundContext(param);
- // 是否全部退款
- if (param.isRefundAll()){
- // 全部退款根据支付订单的退款信息构造退款参数
- List channelParams = payOrder.getRefundableInfos()
- .stream()
- .map(o -> new RefundChannelParam().setChannel(o.getChannel())
- .setAmount(o.getAmount()))
- .collect(Collectors.toList());
- param.setRefundChannels(channelParams);
+
+ // 加锁
+ LockInfo lock = lockTemplate.lock("payment:refund:" + payOrder.getId());
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("退款处理中,请勿重复操作");
+ }
+
+ try {
+ // 退款上下文初始化
+ payRefundAssistService.initRefundContext(param);
+ // 是否全部退款
+ if (param.isRefundAll()){
+ // 全部退款根据支付订单的退款信息构造退款参数
+ List channelParams = payOrder.getRefundableInfos()
+ .stream()
+ .map(o -> new RefundChannelParam().setChannel(o.getChannel())
+ .setAmount(o.getAmount()))
+ .collect(Collectors.toList());
+ param.setRefundChannels(channelParams);
+ }
+ return this.refundByChannel(param,payOrder);
+ } finally {
+ lockTemplate.releaseLock(lock);
}
- return this.refundByChannel(param,payOrder);
}
/**
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java
index 01fb5c77c..c157f25d9 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/service/PaySyncService.java
@@ -1,6 +1,7 @@
package cn.bootx.platform.daxpay.service.core.payment.sync.service;
import cn.bootx.platform.common.core.exception.BizException;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
import cn.bootx.platform.daxpay.code.PaySyncStatusEnum;
@@ -19,6 +20,8 @@ import cn.bootx.platform.daxpay.service.core.record.pay.service.PayOrderService;
import cn.bootx.platform.daxpay.service.core.record.sync.entity.PaySyncRecord;
import cn.bootx.platform.daxpay.service.core.record.sync.service.PaySyncRecordService;
import cn.bootx.platform.daxpay.service.func.AbsPaySyncStrategy;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -48,6 +51,8 @@ public class PaySyncService {
private final PayRepairService repairService;
+ private final LockTemplate lockTemplate;
+
/**
* 支付同步, 开启一个新的事务, 不受外部抛出异常的影响
*/
@@ -75,46 +80,56 @@ public class PaySyncService {
* 2. 如果状态不一致, 调用修复逻辑进行修复
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
- public PaySyncResult syncPayOrder(PayOrder order) {
- // 获取同步策略类
- AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(order.getAsyncChannel());
- syncPayStrategy.initPayParam(order);
- // 记录支付单同步前后的状态
- String oldStatus = order.getStatus();
- String repairStatus = null;
-
- // 执行同步操作, 获取支付网关同步的结果
- GatewaySyncResult syncResult = syncPayStrategy.doSyncStatus();
- // 判断是否同步成功
- if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
- // 同步失败, 返回失败响应, 同时记录失败的日志
- this.saveRecord(order, syncResult, true, oldStatus, null, syncResult.getErrorMsg());
- return new PaySyncResult().setErrorMsg(syncResult.getErrorMsg());
+ public PaySyncResult syncPayOrder(PayOrder payOrder) {
+ // 加锁
+ LockInfo lock = lockTemplate.lock("payment:refund:" + payOrder.getId());
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
}
- // 判断网关状态是否和支付单一致, 同时更新网关同步状态
- boolean statusSync = this.checkAndAdjustSyncStatus(syncResult,order);
try {
- // 状态不一致,执行支付单修复逻辑
- if (!statusSync){
- this.resultHandler(syncResult, order);
- repairStatus = order.getStatus();
- }
- } catch (PayFailureException e) {
- // 同步失败, 返回失败响应, 同时记录失败的日志
- syncResult.setSyncStatus(PaySyncStatusEnum.FAIL);
- this.saveRecord(order, syncResult, false, oldStatus, null, e.getMessage());
- return new PaySyncResult().setErrorMsg(e.getMessage());
- }
+ // 获取同步策略类
+ AbsPaySyncStrategy syncPayStrategy = PaySyncStrategyFactory.create(payOrder.getAsyncChannel());
+ syncPayStrategy.initPayParam(payOrder);
+ // 记录支付单同步前后的状态
+ String oldStatus = payOrder.getStatus();
+ String repairStatus = null;
- // 同步成功记录日志
- this.saveRecord( order, syncResult, !statusSync, oldStatus, repairStatus, null);
- return new PaySyncResult()
- .setGatewayStatus(syncResult.getSyncStatus().getCode())
- .setSuccess(true)
- .setRepair(!statusSync)
- .setOldStatus(oldStatus)
- .setRepairStatus(repairStatus);
+ // 执行同步操作, 获取支付网关同步的结果
+ GatewaySyncResult syncResult = syncPayStrategy.doSyncStatus();
+ // 判断是否同步成功
+ if (Objects.equals(syncResult.getSyncStatus(), PaySyncStatusEnum.FAIL)){
+ // 同步失败, 返回失败响应, 同时记录失败的日志
+ this.saveRecord(payOrder, syncResult, true, oldStatus, null, syncResult.getErrorMsg());
+ return new PaySyncResult().setErrorMsg(syncResult.getErrorMsg());
+ }
+
+ // 判断网关状态是否和支付单一致, 同时更新网关同步状态
+ boolean statusSync = this.checkAndAdjustSyncStatus(syncResult,payOrder);
+ try {
+ // 状态不一致,执行支付单修复逻辑
+ if (!statusSync){
+ this.resultHandler(syncResult, payOrder);
+ repairStatus = payOrder.getStatus();
+ }
+ } catch (PayFailureException e) {
+ // 同步失败, 返回失败响应, 同时记录失败的日志
+ syncResult.setSyncStatus(PaySyncStatusEnum.FAIL);
+ this.saveRecord(payOrder, syncResult, false, oldStatus, null, e.getMessage());
+ return new PaySyncResult().setErrorMsg(e.getMessage());
+ }
+
+ // 同步成功记录日志
+ this.saveRecord( payOrder, syncResult, !statusSync, oldStatus, repairStatus, null);
+ return new PaySyncResult()
+ .setGatewayStatus(syncResult.getSyncStatus().getCode())
+ .setSuccess(true)
+ .setRepair(!statusSync)
+ .setOldStatus(oldStatus)
+ .setRepairStatus(repairStatus);
+ } finally {
+ lockTemplate.releaseLock(lock);
+ }
}
/**
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/task/PayOrderSyncTaskService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/task/PayOrderSyncTaskService.java
deleted file mode 100644
index 8166310c9..000000000
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/task/PayOrderSyncTaskService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.bootx.platform.daxpay.service.core.payment.sync.task;
-
-import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
-import cn.bootx.platform.daxpay.param.pay.PaySyncParam;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-/**
- * 对未过期的支付中订单进行状态同步
- * @author xxm
- * @since 2024/1/1
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class PayOrderSyncTaskService {
- private final cn.bootx.platform.daxpay.service.core.timeout.dao.PayExpiredTimeRepository PayExpiredTimeRepository;
-
- private final PaySyncService paySyncService;
-
- /**
- * 同步支付订单任务
- */
- public void syncTask() {
- log.info("开始同步支付订单");
- // 1. 从超时订单列表中获取到未超时的订单号
- for (String s : PayExpiredTimeRepository.getNormalKeysBy30Day()) {
- try {
- Long paymentId = Long.parseLong(s);
- PaySyncParam paySyncParam = new PaySyncParam();
- paySyncParam.setPaymentId(paymentId);
- paySyncService.sync(paySyncParam);
- } catch (Exception e) {
- log.error("同步支付订单异常", e);
- }
- }
- }
-}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
index 847c96ba8..96ef313a5 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
@@ -1,13 +1,18 @@
package cn.bootx.platform.daxpay.service.core.timeout.task;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.daxpay.param.pay.PaySyncParam;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
import cn.bootx.platform.daxpay.service.core.timeout.dao.PayExpiredTimeRepository;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
+import java.util.Objects;
import java.util.Set;
/**
@@ -20,15 +25,20 @@ import java.util.Set;
@RequiredArgsConstructor
public class PayExpiredTimeTask {
private final PayExpiredTimeRepository repository;
+
private final PaySyncService paySyncService;
+ private final LockTemplate lockTemplate;
-// @Scheduled(cron = "*/5 * * * * ?")
+ @Scheduled(cron = "*/5 * * * * ?")
public void task(){
log.info("执行超时取消任务....");
Set expiredKeys = repository.getExpiredKeys(LocalDateTime.now());
for (String expiredKey : expiredKeys) {
- log.info("key:{}", expiredKey);
+ LockInfo lock = lockTemplate.lock("payment:expired:" + expiredKey,10000,0);
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
+ }
try {
// 执行同步操作, 网关同步时会对支付的进行状态的处理
Long paymentId = Long.parseLong(expiredKey);
@@ -37,6 +47,8 @@ public class PayExpiredTimeTask {
paySyncService.sync(paySyncParam);
} catch (Exception e) {
log.error("超时取消任务 异常", e);
+ } finally {
+ lockTemplate.releaseLock(lock);
}
}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayWaitOrderSyncTask.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayWaitOrderSyncTask.java
index 9899e33a1..1e86fff52 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayWaitOrderSyncTask.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayWaitOrderSyncTask.java
@@ -1,12 +1,16 @@
package cn.bootx.platform.daxpay.service.core.timeout.task;
+import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.daxpay.param.pay.PaySyncParam;
import cn.bootx.platform.daxpay.service.core.payment.sync.service.PaySyncService;
import cn.bootx.platform.daxpay.service.core.timeout.dao.PayExpiredTimeRepository;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import java.util.Objects;
import java.util.Set;
/**
@@ -22,12 +26,17 @@ public class PayWaitOrderSyncTask {
private final PaySyncService paySyncService;
+ private final LockTemplate lockTemplate;
+
public void task(){
log.info("开始同步支付订单");
// 从超时订单列表中获取到未超时的订单号
Set keys = repository.getNormalKeysBy30Day();
for (String key : keys) {
- log.info("key:{}", key);
+ LockInfo lock = lockTemplate.lock("payment:sync:" + key,10000,0);
+ if (Objects.isNull(lock)){
+ throw new RepetitiveOperationException("支付同步处理中,请勿重复操作");
+ }
try {
Long paymentId = Long.parseLong(key);
PaySyncParam paySyncParam = new PaySyncParam();
@@ -36,6 +45,8 @@ public class PayWaitOrderSyncTask {
paySyncService.sync(paySyncParam);
} catch (Exception e) {
log.error("同步支付订单异常", e);
+ } finally {
+ lockTemplate.releaseLock(lock);
}
}
diff --git a/pom.xml b/pom.xml
index e7cdf0381..140d0d28d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,7 +43,7 @@
1.5.4
4.5.2.B
2.2.3
- 2.2.4
+ 2.2.5