通常状况下,异常结构应该区分为三大类:java
对于不一样的第三方服务,什么状况下对应什么异常,可能会有不一样的划分标准,通常状况下有如下规则:数据库
对于涉及到支付、退款等有下单概念的接口或涉及到状态问题时,则须要考虑到一致性的问题。通常状况下有如下要求(第三方服务也叫上游):json
因为第三方服务通常不受控,这里说的一致性每每只能是最终一致性异步
肯定接口当中的惟一标识是哪一个字段,一般是requestNo,这个字段的值将上游数据和本地数据进行一一对应,上游存在的requestNo,本地必须存在url
划分状态:spa
这里的流程能够概述为:code
若是你对上游的信任度较低,能够直接将PROCESSING状态也合并为UNCONFIRMED通一由事务回查处理orm
下面用一段伪代码来描述接口调用的流程:索引
// 开启本地事务
startTrans();
Order order = new Order();
// 惟一请求号
String requestNo = UUID();
order.setRequestNo(requestNo);
order.setState(OrderState.PENDING);
order.save();
// 提交本地事务
commit();
try {
startTrans();
RpcResponse rpcRes = rpcService.requestToRpcCreateOrder(...);
order.setState(OrderState.PROCESSING);
// 若是你的接口能够同步返回业务状态
if(rpcRes.getState() == 'SUCCESS') {
order.setState(OrderState.SUCCESS);
}
if(rpcRes.getState() == 'FAIL') {
order.setState(OrderState.FAIL);
}
order.save();
commit();
} catch(RpcException e) {
startTrans();
// 认为是处理中,等待后续回查
order.setState(OrderState.PROCESSING);
order.save();
commit();
} catch(BusinessException e) {
startTrans();
// 认为是失败
order.setState(OrderState.FAIL);
// 失败时,建议记录rpc响应参数
order.setRpcResponseCode(e.getCode());
order.setRpcResponseMsg(e.getMsg());
order.save();
commit();
} catch(Exception e) {
startTrans();
// 认为是待确认,等待后续回查
order.setState(OrderState.UNCONFIRMED);
order.save();
commit();
}
复制代码
通过上面的流程,数据会剩下UNCONFIRMED 和 PROCESSING 两种状态,所以对这两种状态进行进一步确认,保证数据到达终态。token
事务回查有几种实现方式:
实际上,假如你的rpc请求不需同步返回出去,推荐使用具备事务机制的消息队列,不然利用队列方案须要考虑复杂度的上升程度
那么UNCONFIRMED 和 PROCESSING分别怎么处理呢
对应PROCESSING,处理思路很简单,由于这种状态上游确定可以返回对应的状态(实际上有的上游并不必定),只要查询到对应状态更新为SUCCESS或FAIL便可
对应UNCONFIRMED须要区分上游数据不存在的状况,也就是说上面的事务发起流程当中,上游没有收到咱们的请求,那么咱们须要根据业务状况进行处理:
若是上游存在该记录,则视为PROCESSING状况处理便可
若是你的上游提供异步处理通知,则可按照一样的思路完成事务回查这个阶段
本文简单总结了一下对接第三方服务接口时须要考虑的几个问题:通信标准、异常处理、一致性,实际处理时一般会分为RPC层与Service层来处理,RPC封装通信标准、异常处理的问题,Service层处理一致性问题。最后留下了一个问题还未进行讨论,在入库前、从新发起请求前、异步通知时都须要考虑幂等的问题,下一篇文章针对幂等再来分享几种处理方案吧。