電商交易場景狀態機方案探索及應用

陶然陶然發表於2023-03-31

背景

目前閒魚行業產品有回收、寄賣、驗貨寶等,這些產品在基礎交易模式上引入附加玩法規則,其狀態機相比於普通交易模型更加靈活複雜。基礎交易模型訂單狀態只包含:建立訂單->付款->發貨->確認收貨 。以回收舉例,在中臺基礎交易模型之上,又附加了諸多行業業務狀態,如服務商收貨、質檢、使用者確認質檢等。這些狀態,是透過使用者或服務商等多種角色推進的,而業務狀態的維護也需要閒魚自己來負責。

存在問題

目前,在狀態履約的程式碼邏輯實現上,狀態履約方法內使用IF-ELSE的結構來判斷不同履約動作。在不同的分支裡,根據推進節點的不同,存在不同的引數校驗、業務執行等等操作。這種原始的實現方式,隨著業務的不斷髮展,逐步暴露出以下問題:

  1. 1. 程式碼介面複雜:目前回收業務推進某一個單一狀態的程式碼就已經達到上百行,如果把整個狀態拓撲的所有履約邏輯都寫到一起的話,則整個履約方法將達到上千行,程式碼內聚高、可讀性差。

  2. 2. 模板式程式碼冗餘、無複用:如前置校驗、後置訊息等。

  3. 3. 無整體拓撲檢視:回收場景的這一套程式碼完成後,之後的開發、服務商、測試都不能感知整體的一個拓撲邏輯。現在我們只能使用另外準備的拓撲圖去作為解釋文件,但程式碼上是沒有能力直接把整個拓撲提取出來的。

  4. 4. 可擴充套件性差:如果要增加狀態或者刪除狀態,或者是增加一條履約的邊。那麼開發人員都需要去改if-else。並且開發改起來的時候必須非常的小心謹慎。比如說要加一個狀態,那首先需要整體增加一個else程式碼塊。另外,在每一個之前IF-ELSE分支裡面又需要加上判斷邏輯,單獨處理新加的狀態是否可以做遷移等等,所以擴充套件性是極差的。

此外,橫向來看,在行業交易的不同產品下,還存在許多共性需求:

  • • 狀態拓撲查詢:在服務商接入、測試迴歸等場景,都需要查詢當前業務的狀態拓撲,以知道當前訂單允許推進到哪些狀態。目前只能依靠另外編寫對接文件的方式進行溝通。程式碼沒有直接提取狀態的能力,有可能導致了對接文件的滯後性。

  • • 狀態履約執行:在實際線上履約、對接聯調、程式碼開發、測試迴歸場景中,都需要執行狀態的履約。另外,在不同的場景中,又希望有單獨的定製功能,比如:在開發、測試過程中,只能推進測試訂單,不能推進實際訂單。

  • • 履約記錄復現:對於一筆訂單的狀態推進記錄可以復現,以幫助技術、運營、客服定位問題。

  • • 履約日常監控:對不同的業務,可以統一提供履約結果的監控,業務也可能根據自身需要單獨配置監控和報警。

電商交易場景狀態機方案探索及應用

解決方案

業界狀態機方案調研

業界幾款流行的開源狀態機框架(如spring-statemachine、 squirrel、smart-engine),均適用於典型的透過狀態機管理系統狀態的場景,他們的共性特點是:

  1. 1. 透過狀態機的定義,表達整個系統狀態、控制系統的複雜流轉。

  2. 2. 提供xml、或鏈式呼叫等方式定義狀態機,解決複雜狀態機定義可讀性差的問題;

  3. 3. 每個狀態機需要維護一個例項(物件);

  4. 4. 狀態機物件一般是一個單例的、共享的變數,供整個系統訪問。狀態變換時需要加鎖控制併發。

這幾款狀態機框架通常受管理的物件需要連續的、較長時間的進行跟蹤管理,並伴隨其完整的生命週期。不適用於訂單履約處理,原因是:訂單履約方法一般是無狀態的,記憶體不需要對每個處理的訂單生成狀態機例項。多筆訂單對應多個履約請求、多個執行緒併發呼叫履約方法。我們的需求是做一個輕量級的、僅僅用來支援行業交易履約的場景, 開發同學透過簡單的api就可以定義好拓撲、實現最基礎的一兩個介面就可以直接執行,監控、日誌能力甚至開箱可用。

問題抽象

針對上節最後提出的問題,我們用抽象的思維,思考在狀態流程履約中,哪些是不變的點、哪些是變化的點。

電商交易場景狀態機方案探索及應用

可以看到,不變的操作有:

  • • 狀態校驗

  • • 引數校驗

  • • 履約執行

  • • 後置邏輯

這幾個操作,都是每個狀態的履約中,可以抽象的操作步驟,是不變的點。每個步驟中的實現細節,是根據不同業務變化的點。那麼,我們將不變的流程模板化、將變化的邏輯介面化。

狀態流程處理

透過一個Executor模板化的執行每個狀態履約動作的步驟,如前置判斷(validate)、執行狀態動作(action)、後置動作(postAction)。對於不同的履約執行動作,抽象出PerformProcessor介面,交給業務具體實現。在某個履約流程執行時,Executor會執行對應的PerformProcessor。

電商交易場景狀態機方案探索及應用

拓撲抽象

對於拓撲定義以及狀態流處理定義,進行以下抽象:

電商交易場景狀態機方案探索及應用

狀態流程處理器

下面我們來看下狀態流程處理器PerformProcessor。它是一個介面,
PerformProcessor中定義了以下幾個方法

  • • init: 初始化流程處理上下文

  • • validate:校驗入參

  • • action:執行流程轉換動作

  • • postAction:執行後置邏輯

  • • finalize:執行收尾工作(本方法一定會被執行,無論其他方法是否拋異常)

電商交易場景狀態機方案探索及應用

如上圖,Executor執行器中,會模板化的呼叫這些方法。

拓撲定義

我們期望定義一個簡明易用的API,來將狀態拓撲以及履約處理器串聯在一起,完成整個狀態機的定義,示意如下:

電商交易場景狀態機方案探索及應用

整體框架結構

框架包含三層:核心層、膠水層、業務層。核心層提供純粹的狀態機定義、拓撲構造、執行引擎等能力,設計的薄一些,控制架構防腐化;膠水層引入中臺訂單查詢、更新等能力,相對厚一些,簡化業務適配成本、最佳化業務流程。業務層則基於通用的框架介面,面向業務應用,提供表達能力。

電商交易場景狀態機方案探索及應用

框架核心層
聚焦於三個能力:狀態拓撲定義、拓撲查詢、狀態推進。
狀態拓撲定義對應 FlowBuilder。拓撲查詢和狀態推進對應核心層的 FlowManager,他會查詢FlowDefination(拓撲定義封裝類) 和 呼叫 FlowExecutor 執行 PerformProcessor。
膠水層
在狀態機核心層和業務互動層之間,我們抽取了一層膠水層。目的有兩個

  1. 1. 抽取膠水層,可以讓狀態機核心層更純粹,只關心狀態履約的定義、流轉邏輯,不耦合業務依賴。核心層將相關的資訊定義為泛型,也是這個道理。因為入參、出參、履約上下文不影響狀態機的流轉邏輯,所以核心使用泛型定義。具體型別由上層實現。另外,膠水層中也可以做一些業務相關的通用動作,如記錄狀態轉換日誌等。

  2. 2. 可擴充套件:該層目前使用TC的BizOrder資訊,供閒魚訂單業務使用。但如果需要擴充套件,可以另行封裝其他膠水層,不影響核心層我們看到膠水層宣告瞭上下文泛型為 BizOrderContext, 該物件中包含TC的BizOrderDO、PayOrder等資訊。由於目前閒魚訂單都是依賴中臺訂單,所以目前回收履約、驗貨寶履約等都直接使用BizOrder膠水層即可。但如果某個業務實現需要其他領域的DO,則可以水平擴充套件膠水層。

業務層
最上層是業務互動層,在不同的業務域內,提供不同的履約功能,比如回收、驗貨寶都會單獨封裝對應的履約服務。主要能力:

  1. 1. 對外提供業務履約、測試工具、機器人聯調等能力,可分別做許可權校驗等邏輯

  2. 2. 對內基於膠水層,進行拓撲查詢、狀態推進等動作

配套設施

  • • 訂單推單工具:面向日常開發和測試,業務層基於狀態機框架,封裝了推單工具。針對一筆訂單,可自動獲取當前業務狀態、可履約動作、自定義入參。

  • • 統一日誌&監控:基於框架收口的履約入口,可以提供跨業務統一的日誌格式,進而搭建統一的、開箱可用的履約日誌查詢和監控。

總結

透過抽象訂單狀態履約的通用問題,提出一套輕量狀態機解決方案。解決了業務靈活多變帶來的諸多技術痛點:1.透過狀態機履約處理器的封裝,隔離了每個履約動作的業務邏輯, 解決了介面程式碼複雜、可讀性差的問題;2. 業務可將通用的業務處理邏輯、校驗邏輯等封裝在通用的處理器中,使得相同邏輯可複用,解決了程式碼冗餘、難複用的問題;3. 透過拓撲的抽象,天然的可以獲取到業務的整體狀態拓撲,對於聯調、業務對接等都提供了便利;4. 如遇需求需要調整狀態拓撲,只需修改拓撲定義,即可靈活刪除或者新增狀態拓撲關係

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2931751/,如需轉載,請註明出處,否則將追究法律責任。

相關文章