支付通知思路
2021-10-14 本文已影响0人
wanggs
支付通知思路
MQ延时消息投递异步通知
场景
在第三方支付中,例如支付宝、或者微信,对于订单请求,第三方支付系统采用的是消息同步返回、异步通知+主动补偿查询的补偿机制
-
商户请求交易接口成功。
-
接受银行的异步通知。
-
处理业务,将通知URL和通知的数据放到队列中。通知队列是常驻的。
-
如果通知商户成功/失败更新通知状态。如果通知失败,根据通知间隔重新把通知数据放到通知队列里。
伪代码
/**
* 接收MQ消息
* 业务: 支付订单商户通知
*/
@Slf4j
@Component
public class PayOrderMchNotifyMQReceiver implements PayOrderMchNotifyMQ.IMQReceiver {
@Autowired
private PayOrderService payOrderService;
@Autowired
private MchNotifyRecordService mchNotifyRecordService;
@Autowired
private IMQSender mqSender;
@Override
public void receive(PayOrderMchNotifyMQ.MsgPayload payload) {
try {
log.info("接收商户通知MQ, msg={}", payload.toString());
Long notifyId = payload.getNotifyId();
MchNotifyRecord record = mchNotifyRecordService.getById(notifyId);
if (record == null || record.getState() != MchNotifyRecord.STATE_ING) {
log.info("查询通知记录不存在或状态不是通知中");
return;
}
if (record.getNotifyCount() >= record.getNotifyCountLimit()) {
log.info("已达到最大发送次数");
return;
}
//1. (发送结果最多6次)
Integer currentCount = record.getNotifyCount() + 1;
String notifyUrl = record.getNotifyUrl();
String res = "";
try {
res = HttpUtil.createPost(notifyUrl).timeout(20000).execute().body();
} catch (Exception e) {
log.error("http error", e);
res = "连接[" + UrlBuilder.of(notifyUrl).getHost() + "]异常:【" + e.getMessage() + "】";
}
//支付订单 & 第一次通知: 更新为已通知
if (currentCount == 1 && MchNotifyRecord.TYPE_PAY_ORDER == record.getOrderType()) {
payOrderService.updateNotifySent(record.getOrderId());
}
//通知成功
if ("SUCCESS".equalsIgnoreCase(res)) {
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_SUCCESS, res);
return;
}
//通知次数 >= 最大通知次数时, 更新响应结果为异常, 不在继续延迟发送消息
if (currentCount >= record.getNotifyCountLimit()) {
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_FAIL, res);
return;
}
// 继续发送MQ 延迟发送
mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_ING, res);
// 通知延时次数
// 1 2 3 4 5 6
// 0 30 60 90 120 150
mqSender.send(PayOrderMchNotifyMQ.build(notifyId), currentCount * 30);
return;
} catch (Exception e) {
log.error(e.getMessage(), e);
return;
}
}
}