通常狀況下,異常結構應該區分爲三大類: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層處理一致性問題。最後留下了一個問題還未進行討論,在入庫前、從新發起請求前、異步通知時都須要考慮冪等的問題,下一篇文章針對冪等再來分享幾種處理方案吧。