Kstry框架一種服務編排的實現
阿新 • • 發佈:2022-03-24
Kstry能做什麼?
如果您遇到了以下問題:
- 程式碼複雜、模型文件更新不及時,致使新同學和非技術同學不能短時間內瞭解業務現狀。技術和非技術間對同一業務理解存在分歧而不自知。甚至業務Owner也不能很流暢的描述出自己所負責的業務
- 專案中涉及到許多領域物件,物件間不僅存在複雜的前後依賴關係還相互摻雜沒有明顯邊界,程式碼多次迭代後更是混亂不堪難以維護
- 某業務鏈路由一系列子任務組成,其中需要並行處理一些耗時長且資料間沒有依賴的子任務,但苦於沒有精簡且無程式碼侵入的併發框架
- 維護平臺型產品,為眾多上游業務線提供著基礎服務,但在短時間內應對各個業務方的定製化需求捉襟見肘,更不知如何做好平臺與業務、業務與業務之間的隔離
- 業務流轉資料狀態追蹤困難,只存在於線上環境的偶現問題更是難以排查。需要一種可以通過簡單操作就能將重要節點資料都儲存下來的能力,此能力堪比對鏈路精細化梳理後的系統性日誌列印
- 業務場景多樣,不乏一些複雜的鏈路難以被測試覆蓋。或者三方資料Mock困難,測試成本居高不下
那麼可以嘗試一下Kstry框架,因為其具備:
視覺化
- 框架引入了業界通用的BPMN流程編排語言
- 使用事件節點、任務節點、閘道器節點等元件來描述業務動作和執行線路
- 編排好的圖示模型即為程式碼真實的執行鏈路,通過所見( 圖示模型 )即所得( 程式碼執行 )的方式在技術和業務之間架起一道通用語言的橋樑,使彼此之間溝通更加順暢
服務編排
- 框架通過定義任務節點來劃分領域邊界並實現業務功能,任務節點對應程式碼中Class的某個方法
- 一個獨立的任務節點理論上只承擔著一種業務動作或領域能力
- 輸入完成任務所需引數的最小集,輸出任務完成的結果或處理後的領域物件
- 節點間使用箭頭符號這種視覺化編排手段來保證彼此間的相互作用有序,通過並行閘道器、包含閘道器、排他閘道器等來豐富節點間的執行依賴關係
支援併發
- 無需改動程式碼,僅僅在並行閘道器或包含閘道器上配置 open-async=true,即可將其後的子鏈路並行化
RBAC( Role-based access control )模式
- 針對平臺型服務,首先可以定義編排出通用的鏈路模型
- 模型中的某個任務節點,應對不同業務場景或需求方的訴求時,可以擴充套件不同的服務能力( 比如A、B兩個業務方都需要抽傭的服務,那麼就可以定義一個抽傭的任務節點,然後A業務需要比例抽傭,而B業務需要階梯式抽傭,這時就可以在抽傭的任務節點上再擴充套件兩個不同的抽傭能力 )
- 擴展出來的能力可視作資源,所有的資源都有著獨一無二的資源名稱,攜帶著包含某個資源名稱的許可權物件即可訪問與之對應的資源( 資源也可稱為:擴展出來的服務能力 )
- 一批獨立的許可權物件有著較高的維護成本,所以可依次將某一業務場景所需的全部許可權聚合起來組成角色物件
- 提供平臺能力時,根據引數標識判斷出具體的業務場景或需求方,並找到與之對應的角色,攜帶該角色執行預設的鏈路模型,即可完成定製化的業務訴求
詳見:RBAC模式
流程回溯
流程回溯可以在鏈路執行完之後,拿到結果或者異常之前,列印節點執行日誌或執行自定義回撥方法,可以應對如下問題:
- 檢視執行過節點的資訊如:執行順序、節點耗時、入參、出參、異常資訊等重要資料
- 自定義流程回溯日誌,或者可以在出現異常時才打印詳情日誌
- 檢查節點執行、引數設定等是否符合預期。因為有時結果確實沒有報錯,但並不代表過程一定沒有問題
- 如果鏈路中有自定義角色的操作,檢查最終角色是否符合預期
簡化測試
- 不依賴業務方入參,而是通過Mock業務角色的方式。之後請求攜帶該角色即可完成對包含有待測試服務節點或者能力擴充套件點的個性化業務鏈路的測試
Kstry如何使用?
下面步驟僅為簡單介紹,具體細節請參考使用文件
1、配置引入
<dependency> <groupId>cn.kstry.framework</groupId> <artifactId>kstry-core</artifactId> <version>1.0.5</version> </dependency>
2、專案引入
@EnableKstry(bpmnPath = "./bpmn/*.bpmn") @SpringBootApplication public class KstryDemoApplication { public static void main(String[] args) { SpringApplication.run(KstryDemoApplication.class, args); } }
3、編寫元件程式碼
@TaskComponent(name = "goods") public class GoodsService { @NoticeResult @TaskService(name = "init-base-info") public GoodsDetail initBaseInfo(@ReqTaskParam(reqSelf = true) GoodsDetailRequest request) { return GoodsDetail.builder().id(request.getId()).name("商品").build(); } }
4、定義bpmn配置檔案
5、呼叫執行
@RestController @RequestMapping("/goods") public class GoodsController { @Resource private StoryEngine storyEngine; @PostMapping("/show") public GoodsDetail showGoods(@RequestBody GoodsDetailRequest request) { StoryRequest<GoodsDetail> req = ReqBuilder.returnType(GoodsDetail.class) .startId("kstry-demo-goods-show").request(request).build(); TaskResponse<GoodsDetail> fire = storyEngine.fire(req); if (fire.isSuccess()) { return fire.getResult(); } return null; } }
6、請求測試