Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
20e36d6d86
2 files changed
+41
-6
No files matched your search
+36
-2
@@ -34,6 +34,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
@@ -140,7 +142,7 @@ public class HardAutoVerifyServiceImpl implements HardAutoVerifyService {
|
||||
|
||||
/**
|
||||
* 在任务状态机事务内执行一次自动核销。触发时间、配置开关和订单状态已由任务状态机在订单行锁内预检,
|
||||
* 本方法只负责核销动作本身和可选退库存;任一远程或本地步骤失败都会随任务事务回滚并进入重试。
|
||||
* 本方法只负责核销动作本身;退库存登记为主事务提交后的独立动作,失败降级告警、不回滚已完成的核销。
|
||||
*
|
||||
* @param task 已通过预检的自动核销任务
|
||||
*/
|
||||
@@ -169,10 +171,42 @@ public class HardAutoVerifyServiceImpl implements HardAutoVerifyService {
|
||||
// 静默核销:订单行锁、履约校验、二维码消费与状态条件更新与人工核销完全一致,仅标记核销方式为自动。
|
||||
hardOrderService.autoVerifyReserveOrder(task.getOrderId());
|
||||
if (Objects.equals(task.getRestoreInventory(), YesNoEnum.YES.getCode())) {
|
||||
restoreAutoVerifyInventory(task.getOrderId());
|
||||
// 退库存必须在主事务提交后独立执行:历史订单菜谱校验失败的异常会穿透 fastenerInventory 的事务代理,
|
||||
// 把核销主事务标记 rollback-only,导致"核销成功却整体回滚";提交后执行失败只降级告警。
|
||||
registerRestoreInventoryAfterCommit(task.getOrderId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册核销主事务提交后的退库存动作;无事务同步上下文时(单测等场景)直接执行兜底。
|
||||
*
|
||||
* @param orderId 已完成自动核销的订单 ID
|
||||
*/
|
||||
private void registerRestoreInventoryAfterCommit(Long orderId) {
|
||||
// afterCommit 内的异常会外抛到提交调用方,必须整体兜底:退库存是尽力而为的修正动作,任何失败只告警。
|
||||
Runnable action = () -> {
|
||||
try {
|
||||
restoreAutoVerifyInventory(orderId);
|
||||
} catch (Exception exception) {
|
||||
log.warn("{}提交后自动核销退库存失败,已降级跳过,orderId:{},exceptionType:{}", TAG, orderId,
|
||||
exception.getClass().getSimpleName());
|
||||
}
|
||||
};
|
||||
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
action.run();
|
||||
return;
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
/**
|
||||
* 核销事务提交完成后按剩余有效数量回补线上池库存,内部自带降级捕获,不影响已提交的核销结果。
|
||||
*/
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
action.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理端在自动核销候选列表逐单立即核销。核销仍走自动核销链路(核销方式标记为自动),
|
||||
* 允许提前关闭尚未到期订单;状态机为保留失败日志会吸收业务异常,因此执行后必须复查最终状态。
|
||||
|
||||
+5
-4
@@ -131,9 +131,9 @@ class HardAutoVerifyServiceImplTest {
|
||||
verify(hardOrderService, never()).fastenerInventory(any(), anyList(), any(), any(), anyString());
|
||||
}
|
||||
|
||||
/** 订单商品全部退款后无可恢复库存,核销事务应失败回滚并交由任务重试与人工排查。 */
|
||||
/** 订单商品全部退款后无可恢复库存,退库存降级告警即可,核销本身照常完成不阻断。 */
|
||||
@Test
|
||||
void completeAutoVerifyShouldFailWhenNoRestorableProduct() {
|
||||
void completeAutoVerifyShouldDegradeWhenNoRestorableProduct() {
|
||||
HardAutoRefundTaskEntity task = task(YesNoEnum.YES.getCode(), LocalDateTime.now().minusMinutes(1));
|
||||
when(hardOrderMapper.selectById(1L)).thenReturn(HardOrderEntity.builder().id(1L).build());
|
||||
HardCarVo fullyRefunded = new HardCarVo();
|
||||
@@ -142,9 +142,10 @@ class HardAutoVerifyServiceImplTest {
|
||||
fullyRefunded.setEffectiveProductCount(0);
|
||||
when(hardCarService.getByOrderId(1L)).thenReturn(List.of(fullyRefunded));
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class, () -> service.completeAutoVerify(task));
|
||||
service.completeAutoVerify(task);
|
||||
|
||||
assertEquals("自动核销订单没有可恢复库存的商品", exception.getMessage());
|
||||
verify(hardOrderService).autoVerifyReserveOrder(1L);
|
||||
verify(hardOrderService, never()).fastenerInventory(any(), anyList(), any(), any(), anyString());
|
||||
}
|
||||
|
||||
/** 天数配置非法时重扫直接拒绝,不触碰任何订单和任务。 */
|
||||
|
||||
Reference in new issue
Block a user