作者:vivo 網際網路伺服器團隊- Cheng Wangrong
本文是《vivo營銷自動化技術解密》的第4篇文章,分析了在營銷自動化業務引入工作流技術的背景和工作流引擎的介紹,同時介紹了幾種業界流行的開源工作流引擎特點,以及在專案自研開發過程中的設計思路和總結思考。
《vivo營銷自動化技術解密》系列文章:
一、業務背景
營銷自動化平臺可以支援不同使用者生命週期的活動旅程策略配置 ,根據使用者觸發的不同活動行為,進行差異化的營銷觸達方案。同時各種型別活動的具體執行過程中也有不同的業務處理流程(比如審批流程和業務流轉)。
業務流程複雜多樣,需求變更頻繁,專案開發過程中會有以下痛點:
- 專案交付週期長:一個完整的業務流程需要從頭開始按版本迭代,開發時間長,成本高。
- 功能重複開發測試:業務之間會摻雜著很多共性的流程,導致大量重複性開發測試工作,效率低。
- 維護成本高:隨著專案業務的逐步發展,業務流程逐步積累,可維護性下降,系統改動牽一髮而動全身。
如何將業務邏輯從控制流中剝離出來,讓產研人員更聚焦於業務的實現是需要重點解決的問題。而傳統OA領域使用的是久經考驗的業務流程管理解決方案 —— 工作流(Workflow)。工作流是一套工業級的解決方案,由工作流管理聯盟(WfMC)制定了一系列的標準。
二、工作流介紹
2.1 工作流定義
工作流(Workflow)—— 對工作流程及其各操作步驟之間業務規則的抽象,將流程中的工作組織邏輯和規則進行建模,交由計算機進行自動處理。
工作流的本質思想是:通過預定義的工作流程模板,對現實活動進行例項化的過程。簡單說就是通過預設的格式或者視覺化配置好流程的模板(比如一種分享活動的執行流程模板),使用時通過該模板構造出一個流程例項物件,通過例項物件完成活動執行跟蹤和回溯。
2.2 工作流參考模型
WfMC工作流管理聯盟為工作流制定了參考模型,其核心就是中間的工作流引擎,工作流引擎提供流程定義工具(介面1)、給使用者提供資訊查詢(介面2)、呼叫外部應用(介面3)、整合其他工作流(介面4)和監控管理(介面5)的能力。 對於大多數工作流產品而言,重點關注的是介面1和介面2的實現。
2.3 工作流引擎關鍵特性
- 流程視覺化
提供視覺化的流程搭建,流程檢視檢視能力,以及實時觀測任務執行能力。
- 業務可編排複用
將公共業務進行元件化,可以支援任務的自由編排,自由搭建出適合的業務的不同流程。
- 業務和控制分離
將流程的控制(如流轉、判斷、迴圈、重試等)的任務交由工作流負責,讓使用者聚焦於核心業務邏輯。
2.4 工作流引擎的型別
對於工作流的型別沒有專門的標準,按照流程任務節點特性可以分為:
- 順序工作流
順序工作流的執行方式類似一種特定的流程圖,上一個流程任務完成後依次進入下一個流程任務,過程不可逆。
- 狀態機工作流
狀態機工作流側重關注的是流程任務的狀態,驅使任務狀態發生變化的因素一般為外部事件,即事件驅動的方式,驅使任務節點從一個狀態執行到另外一個狀態,節點間可逆。
- 規則驅動工作流
側重於節點的運轉規則,基於業務規則進行工作流程的執行,在處理具有明確目標但“規則”或規範級別不同的各種專案時,規則驅動的工作流非常有用。
可以看到不同型別的工作流不是完全割裂的,狀態機工作流中也可以結合著條件和規則進行操作節點轉換的過程。在軟體開發中,一般會考慮結合狀態機和規則驅動的工作流。
2.5 工作流引擎和狀態機的差異
在之前的文章裡面,我們有對狀態機和工作流引擎做過一次簡單的對比,事實上,兩者之間並不是一個完全對等的概念:
- 狀態機是系統狀態以及這些狀態之間轉移和動作等行為的數學計算模型,而工作流是對整體工作流程及其各操作步驟之間業務邏輯和規則的抽象建模。
- 狀態機模式是事件驅動型,大多通過外部事件觸發狀態的自動流轉;工作流引擎更側重於描述預定義流程任務完成之後的自動流轉,可預測性會更強。
- 從適用場景的複雜性上看,直接使用狀態機的方式可以清晰地描繪出所有可能的狀態以及導致轉換的事件,適用於解決單維度、複雜度不高的業務問題,發揮靈活輕便的特點;工作流引擎則更適合複雜的業務流程管理,解決如大型CRM複雜度更高的流程自動化問題,聚焦於改善整體業務流程的效率。
- 工作流引擎是可以在狀態機的結構模型基礎上進行構建,事實上很多開源的工作流引擎也都是基於狀態機的實現方式。
瞭解了工作流的基本特點和使用場景之後,我們來看一下比較流行的開源工作流引擎。
三、開源工作流引擎
四、工作流引擎自研設計
4.1 使用開源工作流引擎的問題
- 開源工作流最大的優勢是可以藉助開源的資源,開箱即用,功能全面,但是與之帶來的是附帶的配置和表數量比較多的維護問題。以Activiti為例,使用Activiti7.0版本至少要引入二十多張表,雖然說看似是無侵入的方式,但是系統演進和維護過程中有一定的成本。特別是業務流程例項很多的時候,開發人員需要對錶邏輯有更深的把控。
- 由於業務的客觀獨特性,作為業務流程元件,一般都需要根據自身業務進行二次開發適配。 比如需要根據自身組織架構,進行流程節點使用者角色許可權的管控;將自身的業務能力外掛化,加入工作流程配置中,進行攔截回撥等。
4.2 自研引擎核心設計思路
4.2.1 引擎核心模組
迴歸工作流的本質, 工作流是通過預定義的流程模板,對現實活動進行例項化的過程。一個基本的工作流引擎主要包括三大核心部分:
- 流程模板建立
根據業務規則和邏輯,建立流程模板,設定每一個節點的操作和變更路徑。基於模板建立,可以延伸出流程設計器、外掛式節點,多樣化的模板檔案格式、模板持久化等。
- 流程例項釋出
根據流程模板,建立一個流程例項,流程模板和流程例項的關係類似類和物件的關係。比如說工單系統管理員定義好一個審批流模板(流程模板),使用者點選建立一個工單(流程例項)。基於流程例項釋出,又可以延伸出例項實時觀測,節點變遷記錄回溯,例項狀態持久化,失敗重試,事務控制等。
- 任務流程執行
建立好流程例項之後,流程例項只需要按照流程模板的定義獨立執行各自例項的任務,不同的例項之間互不影響,完成各自例項的生命週期。
4.2.2 引擎核心設計
① 應用容器啟動時,載入流程引擎環境配置,包括解析器構造,流程引擎上下文,流程定義檔案路徑等。
② 讀取定好的流程定義檔案,進行流程節點解析,構建好執行上下文,將流程節點放到記憶體快取中。
③ 業務側進行流程建立,啟動一個新的流程例項,同時將業務流程和流程例項進行繫結。
④ 執行流程例項各個節點,將每個流程節點進行持久化儲存。
4.3 具體實踐
① 引擎核心服務。
引擎操作的主要對外介面,包括啟動流程例項,和獲取相關流程定義模板,流程例項,流程節點的服務。
public interface FlowEngine {
/**
* 根據流程定義key,引數列表啟動流程例項
*
*/
FlowInstance startInstance(String processDefKey, Map<String, Object> args);
/**
* 根據流程定義主鍵ID,引數列表執行流程任務(推動流程自動流轉)
* 統一事務控制
*/
void execInstance(Long instanceId, Map<String, Object> args) throws FlowAuthorityException;
/**
* 獲取流程定義process服務
*
*/
ProcessService process();
/**
* 獲取流程例項服務
*
*/
InstanceService instance();
/**
* 獲取任務節點服務
*
*/
TaskService task();
}
② 流程定義服務。
主要是針對流程定義模板的建立和釋出,可以根據具體的實現類來支援不同的建立方式。
public interface ProcessService {
/**
* 建立流程定義模板
*
*/
void create(String definition);
/**
* 釋出流程定義模板
*
*/
void deploy(String fileName);
/**
* 獲取流程key對應的流程定義
*/
FlowProcess getProcessByDefKey(String processDefKey);
}
③ 流程例項服務。
提供流程例項建立持久化和流程例項執行的入口。
public interface InstanceService {
/**
* 建立流程例項
*
*/
FlowInstance createInstance(FlowProcess process, Map<String, Object> args);
/**
* 執行流程例項
*
* @param instanceId 流程例項id
*/
void exec(Long instanceId);
/**
* 根據id獲取流程例項
*
* @param instanceId
* @return
*/
FlowInstance getById(Long instanceId);
}
④ 流程任務節點服務。
提供流程節點具體每個任務的建立和查詢。
public interface TaskService {
/**
* 根據任務模型、執行物件建立新的任務
*
*/
FlowTask createTask(TaskModel taskModel, Execution execution);
/**
* 完成任務
*
*/
FlowTask complete(Long taskId, Map<String, Object> args);
/**
* 獲取流程例項中正在進行的任務
*
*/
FlowTask getActiveTask(Long instanceId);
/**
* 獲取流程例項上一個已完成的任務
*
*/
FlowHistTask getLastDoneTask(Long instanceId);
}
其中核心的方法就是
FlowEngine#startInstanceByKey,啟動流程例項。基於流程定義,建立一個流程例項物件。
FlowEngine#execInstance,執行流程例項任務,通過傳入的上下文引數(操作人,操作變數等),按照流程定義的節點任務,推進流程例項的自動流轉。
4.4 思考和擴充套件
- 流程定義解析效能。
由於目前設計是在應用啟動時對所有的流程定義檔案進行載入和解析,流程定義檔案過多時會影響應用啟動速度,可以通過多執行緒解析和懶載入(使用時解析)兩種方式進行優化。
- 流程定義版本相容性。
由於業務流程不是一成不變的,在專案發展過程中會不斷進行迭代,需要對前面不同的流程進行相容。
- 流程節點外掛化和編排能力。
將基礎服務進行提取公用,以支援繪製不同流程的外掛化和編排能力。
- 流程執行監控能力。
對流程任務節點執行情況進行埋點上報,系統自動進行監測告警。
五、總結
本文分析了引入工作流引擎的背景,驅使業務邏輯從控制流中剝離出來,讓產研團隊更聚焦於業務,解決研發效率低的問題。
工作流的本質思想是通過預定義的工作流程模板,對現實活動進行例項化的過程。一般需要具備流程視覺化、業務可編排複用、 業務和控制分離的基本能力。一般常見的工作流分為順序工作流、狀態機工作流和規則驅動工作流,開源工作流框架中最常見的是狀態機工作流,利用事件驅動的方式,驅使流程運轉。
同時簡單介紹了業界比較流行的幾種開源工作流引擎的特點,結合開源工作流引擎的特點的問題,並且針對多樣化和迭代頻繁的業務流程, 以工作流的本質思想為出發點,我們自研了一套輕量級的工作流引擎,分享了在實踐過程中的設計思路和總結思考。