拼团对接支付系统之后,想梳理一下
这里是一个区分逻辑,判断是普通订单还是拼团订单。
通过检查 MarketType(营销类型)字段,
-
普通订单: 走
else分支,直接调用repository.changeOrderPaySuccess,这会立即变更状态并发送EventBus消息触发发货。 -
拼团订单: 走
if分支,进入“等待拼团”流程。
@Override
public void changeOrderPaySuccess(String orderId, Date payTime) {
OrderEntity orderEntity = repository.queryOrderByOrderId(orderId);
if (null == orderEntity) return;
if (MarketTypeVO.GROUP_BUY_MARKET.getCode().equals(orderEntity.getMarketType())) {
repository.changeMarketOrderPaySuccess(orderId);
// 发起营销结算。这个过程可以是http/rpc直接调用,也可以发一个商城交易支付完成的消息,之后拼团系统自己接收做结算。
port.settlementMarketPayOrder(orderEntity.getUserId(), orderId, payTime);
// 注意;在公司中,发起结算的http/rpc调用可能会失败,这个时候还会有增加job任务补偿。条件为,检查一笔走了拼团的订单,超过n分钟后,仍然没有做拼团结算状态变更。
// 我们这里失败了,会抛异常,借助支付宝回调/job来重试。你可以单独实现一个独立的job来处理。
} else {
repository.changeOrderPaySuccess(orderId, payTime);
}
}
如果确认为拼团订单,系统不会立即发货,而是执行了以下两步关键操作:
1)repository.changeMarketOrderPaySuccess(orderId)将订单状态改为 PAY_SUCCESS(支付成功),但没有触发发货的 EventBus 消息。
2)调用 port.settlementMarketPayOrder(...)穿透到了 Infrastructure 层,ProductPort 使用 Retrofit 构建了一个 HTTP POST 请求,将 Source、Channel、UserId、OrderId 发送给外部的 GroupBuyMarket(拼团系统)。
@Override
public void settlementMarketPayOrder(String userId, String orderId, Date orderTime) {
SettlementMarketPayOrderRequestDTO requestDTO = new SettlementMarketPayOrderRequestDTO();
requestDTO.setSource(source);
requestDTO.setChannel(chanel);
requestDTO.setUserId(userId);
requestDTO.setOutTradeNo(orderId);
requestDTO.setOutTradeTime(orderTime);
try {
Call<Response<SettlementMarketPayOrderResponseDTO>> call = groupBuyMarketService.settlementMarketPayOrder(requestDTO);
// 获取结果
Response<SettlementMarketPayOrderResponseDTO> response = call.execute().body();
log.info("营销结算{} requestDTO:{} responseDTO:{}", userId, JSON.toJSONString(requestDTO), JSON.toJSONString(response));
if (null == response) return;
// 异常判断
if (!"0000".equals(response.getCode())) {
throw new AppException(response.getCode(), response.getInfo());
}
} catch (Exception e) {
log.error("营销结算失败{}", userId, e);
}
}
此时流程暂停,等待拼团系统的“回信”。
几个问题,可能会拷打:
1. changeMarketOrderPaySuccess,然后才调用远程接口 port.settlementMarketPayOrder。如果本地库更新成功了,但远程 HTTP 请求超时或失败了(比如断网),这笔订单会发生什么?
需要补偿机制,job定时任务扫描数据库一直在PAY_SUCCESS超过N分钟(未变为DEAL_DONE)重新触发settlementMarketPayOrder
2.关于“异步回调”的设计
提问: “为什么拼团系统结算完成后,不直接在 settlementMarketPayOrder 的 HTTP 响应里返回‘拼团成功’,而是要单独搞一个 groupBuyNotify 接口?”
-
解耦与耗时: 支付成功(结算)≠拼团成功。用户A支付后,可能还要等用户B、用户C支付才能成团。这个过程可能持续几小时。HTTP 请求不可能挂起几小时等待
流程闭环: 拼团系统确认成团后,主动回调商城的groupBuyNotify->orderService.changeOrderMarketSettlement->EventBus发送消息 -> 触发发货。
@Override
public void changeOrderMarketSettlement(List<String> outTradeNoList) {
// 更新拼团结算状态
orderDao.changeOrderMarketSettlement(outTradeNoList);
// 循环成功发送消息 - 一般在公司的场景里,还会有job任务扫描超时没有结算的订单,查询订单状态。查询对方服务端的接口,会被限制一次查询多少,频次多少。
outTradeNoList.forEach(outTradeNo -> {
BaseEvent.EventMessage<PaySuccessMessageEvent.PaySuccessMessage> paySuccessMessageEventMessage = paySuccessMessageEvent.buildEventMessage(
PaySuccessMessageEvent.PaySuccessMessage.builder()
.tradeNo(outTradeNo)
.build());
PaySuccessMessageEvent.PaySuccessMessage paySuccessMessage = paySuccessMessageEventMessage.getData();
eventBus.post(JSON.toJSONString(paySuccessMessage));
});
}
大概流程:
-
普通单:
PAY_WAIT->PAY_SUCCESS-> (EventBus) ->SELL_DONE。 -
拼团单:
PAY_WAIT->PAY_SUCCESS(钱到了) -> RPC调用 -> (等待回调) ->DEAL_DONE(团成了) -> (EventBus) ->SELL_DONE。
而提到:通过 ProductPort 连接拼团系统。在 DDD架构中,为什么要设计这个 Port?直接在 Service 层写 HTTP 请求不可以吗?
跟一些原则有关,依赖倒置原则···。而port通常是适配器(Adapter),它实现了领域层的接口,底层确实是 HTTP,使得商城业务逻辑不依赖于具体的拼团API细节。
3.关于这个结算:为什么支付成功后,要先调用拼团系统的‘结算’接口?为什么不能等拼团满员了再统一结算?如果这单是拼团的第一单(开团),和第 N 单(参团)的处理逻辑在接口对接上有什么区别吗?”
这里的“结算”是作为“确认参团”**
4.支付宝的回调可能会发送多次(重试机制),拼团完成的通知也可能因为网络抖动发送多次。接口如何保证幂等性?如果同一个订单被处理了两次,会不会导致发了两次货?
public void changeOrderPaySuccess(String orderId, Date payTime) {
// 1. 先查数据库当前状态
OrderEntity order = repository.queryOrderByOrderId(orderId);
// 2. 幂等判断:如果状态已经是“支付成功”或“交易完成”,直接返回!
// 这里的关键是:只能从 PAY_WAIT 流转到 PAY_SUCCESS
if (!OrderStatusVO.PAY_WAIT.getCode().equals(order.getStatus())) {
log.info("订单[{}]状态已经是[{}],忽略重复的支付回调", orderId, order.getStatus());
return; // 直接结束,不做任何操作
}
// 3. 只有状态是 PAY_WAIT,才执行后续的 Update 和 EventBus
// ... 执行原有逻辑
}
拼团支付系统设计与思考
668

被折叠的 条评论
为什么被折叠?



