業務方訂單審覈經過後,會有離線任務不斷輪訓向支付中心發起調用,支付中心打款處理完成後會返回ifSuccess(是否落庫),state,code,error Message等。若是落庫且code爲打款成功,訂單業務狀態會修改成打款成功。php
爲了配合業務發展,會增長各類活動來拉動訂單量,有些活動有打款需求,由於業務處於快速發展期,實現方案都是在業務訂單向支付中心發起調用後,把與訂單有關的活動打款也向支付發起調用。待打款都成功後,再分別將業務訂單和活動的狀態置爲打款成功。前端
1.支付中心打款成功須要知足不少條件好比:爲每一個場景分配的財務編碼須要在有效期,財務編碼額度須要足夠,用戶須要有第三方的openId進行打款等。一旦某個打款狀況出現問題會致使,其他相關的業務都會被阻塞(主業務訂單狀態的修改會在最後,由於離線任務是輪訓的是未打款成功的訂單,即與訂單相關活動的打款依賴於訂單的重試功能)ios
2.相關代碼耦合愈加嚴重,訂單發起打款的代碼裏冗雜了愈來愈多各個活動的打款代碼,後續開發和維護成本愈來愈高。c++
3.打款異常狀況愈加增多,天天都須要rd分攤不少時間去幫助客服查詢訂單未完結或者沒有收到某個打款的緣由。git
1.經過相似spring的擴展點模式,將各個活動的打款代碼抽離出去,從代碼可讀性和易維護開發性上講好了許多,可是依然會有訂單狀態阻塞狀況出現,各個打款直接也會相互影響,排查問題也會較爲困難。es6
2.提供客服查詢工具,讓用戶能夠根據訂單id查詢業務訂單和相關活動的打款狀況。可是增長新的活動還須要繼續完善客服查詢工具,且當調用支付中心由於用戶帳號沒有落庫(落庫後支付中心會經過各類機制保障打款成功)時,失敗信息只會記錄在日誌(沒有被收集在hive)中,兩邊都不可查詢。當客服提供一個好久以前的打款問題訂單時,查詢會很是麻煩。web
剝離業務訂單打款與活動打款的耦合,保障業務訂單打款必定成功,結合業務狀況考慮,不對活動打款進行強一致處理,活動打款失敗的少數狀況,由客服處理。spring
以前打款問題查詢困難,佔用開發時間過多,後續活動打款須要新增長開發時間,有一些問題查詢困難,但願能夠給客服更方便的查詢打款方式sql
新開發的打款方案要作到方便業務調用,內部的邏輯與業務鬆耦合,只須要提供給業務插入打款和查詢打款的能力數據庫
經過聚攏各個狀況下的打款,作到統一監控,配合統計日誌,設置關鍵項目(財務編碼過時,打款金額)的報警及監控,統計錯誤打款郵件發送的功能
爲了保障系統安全平穩上線,採用小步迭代的方式,先選取一個活動調用打款服務,其他的打款狀況依然調用支付中心。打款服務提供插入接口插入待打款記錄和離線任務輪訓打款記錄發起打款。
爲了保證打款id的全局惟一性(固然也可使用更好地保障全局惟一的id生成方式),也爲了作到業務的高度聚合,打款id由以前的使用各個打款狀況的業務id變爲在插入打款記錄時生成打款id。
插入接口參數:用戶id,業務類型,打款計劃id,金額,業務id,開始打款時間(能夠爲空),打款描述(將會展現在用戶的微信收款記錄中),mchid,訂單id
業務類型與業務id會在數據庫中設置惟一索引,來保障惟一性。經過業務類型的方式也避免了不一樣業務可能存在的業務id衝突的問題,也可使得打款服務能夠支撐將來其它業務的接入。
開始打款時間能夠不傳,傳遞時離線任務只會查詢開始打款時間在當前時間以前的。
打款描述,打款計劃id,mchid爲業務方屬性,打款服務不與業務耦合,因此由業務方傳遞。
訂單id能夠不傳,傳遞時是爲與某個訂單相關的打款,不傳時視爲單獨的打款記錄。
離線任務輪選打款服務
離線任務應用與打款服務之間採起逐筆調用的方式是爲了不數據過大引起接口超時。最終job執行成功後,也會在任務平臺能夠觀測到job的運行狀況,若是任務執行超時也會影響觀測結果。在調用支付中心後再也不像以前同樣只根據打款是否成功進行狀態變化,會把支付返回來的全部錯誤code和message記錄在這條打款記錄的數據中。也會記錄相應的統計日誌,供數據平臺抓取。
第一步的設計過程當中有一個難點,以前的業務是直接用業務id調用支付中心的,每一筆調用雖然冪等可是不能保證當即打款給用戶,而業務訂單狀態和活動打款狀態都會在支付中心返回確認打款成功以後,才變爲打款成功狀態,不然業務會重試調用支付。由於如今打款服務的插入接口中會本身生成打款id,若是打款id不一樣,就有可能形成屢次打款。咱們考慮了兩種解決方案,第一種是數據遷移,這種方案在遷移過程當中須要暫停線上業務的打款,須要人工關注各個業務的數據是否正常,在對用戶的影響和人工消耗方面都是很大的。第二種方案,在打款服務插入接口中,冗餘一部分代碼來處理兼容,每次插入記錄以前都先用業務id去支付中心查詢,若是能查到結果(說明曾經用它做爲打款id打款),則把業務id同同時也做爲打款id記錄。
在版本1上線穩定運行一段時間後,打款服務已經作好了接入其它打款場景的準備。根據現有業務狀況,咱們選擇業務訂單的打款同步調用打款服務插入接口,其他訂單關聯活動在消費訂單狀態變化的mq時調用打款服務插入接口。這樣既實現了業務訂單與訂單關聯活動的解耦,也使得活動的代碼內聚,從而減小了問題排查的成本和後期代碼的維護工做量。
當打款的事情都完成後,就開始着手提供給客服更好地查詢工具以緩解開發人工介入的成本。以前的查詢工具問題在於,打款失敗問題不明確,有新的活動都須要從新增長查詢代碼。
在打款服務插入接口中,咱們容許業務方傳入訂單id,咱們會將傳入的訂單id記錄在該條記錄當中,查詢打款記錄時,只須要提供訂單id,就能夠將相關的打款一連串的查詢出來,咱們只須要將業務類型對應的實際活動告知客服方或者在前端代碼中增長一個枚舉項便可,打款失敗的錯誤信息由於完善的記錄,咱們能夠都展現給客服,客服能夠根據明確的問題,直接找到問題解決方,避免了業務方開發在中間作中介的人工消耗。
打款服務上線一段時間後,一個用戶體驗問題暴露了出來,爲了代碼高度解耦,最初的設計中,只要業務訂單調用打款服務插入接口返回成功後,業務訂單就能夠將訂單狀態置爲打款成功,由打款服務保障段成功。可是這麼作可能會在一些場合下,用戶看到訂單狀態已是打款成功了,可是實際上沒有收到錢,會給用戶很很差的用戶體驗。
咱們採起在打款服務中提供打款查詢接口,根據業務類型和業務id查詢打款狀況,業務訂單在輪訓未打款成功訂單,插入打款服務後,會接着調用查詢打款服務,只有查詢結果爲打款成功後纔將業務訂單狀態修改成打款成功。
版本五迎來了最大的變化,本來的打款服務只支持微信打款,而隨着業務的拓展將來可能會有qq打款和支付寶打款的狀況。爲了實現qq生態和阿里生態的業務推廣,對應的打款服務也須要具有這樣的能力。
根據業務狀況,微信打款和qq打款是得到用戶的微信或者qq的openid進行打款,能夠做爲常規打款渠道,支付寶打款是讓用戶填寫支付寶帳號和姓名進行打款,只能是用戶綁定微信或者綁定qq帳戶失效後的一個備用渠道,且出於安全考慮用戶輸入一次支付寶打款信息,只能將用戶填寫以前的帶打款金額打給用戶,下次須要支付寶打款時,須要用戶從新綁定支付寶。
爲了知足上面說的業務場景,咱們增長了一個用戶支付寶信息記錄表,以及一個支付寶打款離線任務,插入接口新增參數:渠道是否明確,打款方式,打款計劃與渠道的對應map,old打款id,業務打款建立時間。
以前的離線打款任務也作了一些調整,根據業務狀況。即便用戶綁定了支付寶,咱們也要優先給用戶使用微信或者qq打款。在打款時會先判斷渠道是否明確(微信或qq生態),若是渠道明確則沿用以前的打款邏輯,若是渠道不明確,先嚐試微信打款,查詢沒有打款成功後,再次嘗試qq打款,查詢沒有打款成功後,修改記錄狀態爲待支付寶打款。
支付寶離線任務會查詢啓用狀態的支付寶帳戶記錄,而後根據記錄去找尋在該記錄建立時間以前存在的待打款記錄,修改改記錄的狀態,而且新插入一條打款記錄(渠道明確指定支付寶打款)。後續流程能夠沿用以前的設計。
有三個在設計點在設計之時着重考慮了下,從嘗試給未知渠道打款到生成新的打款記錄都用的是同一個打款id,(支付寶離線任務會在添加記錄時把原打款id傳入)而沒有在新生成的時候沿用版本一的方式新生成打款id,就是但願經過打款id的一致確保不會由於異常狀況出現多打款的狀況。
插入接口須要傳入打款計劃和業務對應關係map,是由於不一樣的業務不一樣去打的打款計劃id可能會有多個,在嘗試打款的狀況下,業務方並不會指明打款方式和傳入惟一的打款計劃id,若是再打款服務內記錄每一個活動可能的打款計劃id,會讓打款服務與業務高度耦合。因此經過{「weixin」:123,"qq",231}相似的方式來得到。
支付寶信息記錄表設置中間狀態,在中間狀態時不容許用戶綁定新的支付寶帳戶。是擔憂用戶在支付寶離線任務運行過程當中綁定新的支付寶,或者在job運行期間還有新的訂單。 形成用戶認爲的支付寶打款帳戶和實際不一致,或者訂單漏打的狀況。
狀態流轉圖
迭代是沒有盡頭的,寫此文的時候就已經有了很多新改動須要設計了。但願這個系統能夠愈來愈完善,也但願此文能夠給你們參考。