脈絡:Routing Slip 示範了如何讓訊息穿過一連串動態決定的處理步驟。但它的解法建立在兩個關鍵假設上:步驟順序必須事先決定,而且順序是線性的。
許多情況下這兩個假設都不成立——路由決策可能得依中間結果做出;步驟也可能不是循序的,而是多個步驟平行執行。
前面各方案的極限#
Pipes and Filters 的主要優勢之一,是能用通道把個別處理單元串成一個序列。若要能為每則訊息改變順序:
- 用多個 Content-Based Router——彈性最大,但路由邏輯分散在許多路由元件上。
- 用 Routing Slip——透過事先計算訊息路徑提供了中央控制點,但無法依中間結果重新路由,也無法同時執行多個步驟。
若在每個處理單元之後都把控制權交回一個中央元件,就能同時獲得彈性與中央控制。這會形成交替的流程:中央元件 → 處理單元 → 中央元件 → 處理單元……
但這樣一來,中央元件每收到一則訊息,就得依**中間結果與序列中的當前「步驟」**決定下一步——這要求各處理單元回傳足夠的資訊供它判斷,於是處理單元就相依於中央單元的存在(它們得傳遞一些對自己無關、只對中央元件有意義的資訊)。
若想把個別處理步驟與訊息格式和中央單元解耦,就必須給中央單元某種「記憶」,告訴它序列中最後執行的是哪一步。
解法#
先說清楚:Process Manager 的設計與組態是相當龐大的題目,光是工作流程或業務流程管理相關的模式大概就能填滿另一本書。因此本模式的用意主要是「收束」路由模式這個主題,並為工作流程與流程建模指出方向,絕非對業務流程設計的完整處理。

圖 7-20:Process Manager 解法示意
輻輳式訊息流#
使用 Process Manager 會產生所謂的**輻輳(hub-and-spoke)**訊息流:
- 一則進站訊息初始化 Process Manager——稱為觸發訊息(trigger message)
- 依內部規則,它送訊息 (1) 給第一個處理步驟(處理單元 A)
- A 完成任務後回送一則回覆訊息給 Process Manager
- Process Manager 決定下一步,送訊息 (2) 給下一個處理單元
於是所有訊息流量都經過這個中央「樞紐」。
這個中央控制元素的缺點,是有把 Process Manager 變成效能瓶頸的危險。
事實上許多 EAI 廠商想讓你相信「每個整合問題都是流程問題」。但對每種情況都動用 Process Manager 可能是殺雞用牛刀——它會分散你對核心設計議題的注意力,也造成可觀的效能開銷。
管理狀態#
Process Manager 的關鍵功能之一,是在訊息之間維護狀態。
例如第二個處理單元回傳訊息時,Process Manager 必須記得「這是一長串步驟中的第 2 步」。我們不想把這份知識綁在處理單元上,因為同一個單元可能在同一流程中出現多次——處理單元 B 可能同時是第 2 步與第 4 步,於是它送回的同一則回覆訊息,可能該觸發第 3 步或第 5 步,端看流程脈絡。
除了當前位置之外,Process Manager 能儲存額外資訊也很有價值:
它可以保存先前處理的中間結果。例如第 1 步的結果對後面某一步有用,Process Manager 就能存下來,而不必讓後續處理單元的來回訊息一路揹著這份資料——這讓個別處理步驟彼此獨立,不必操心其他單元產生或消費的資料。
實際上,Process Manager 在這裡扮演的是 Claim Check 的角色。
流程實例#
因為流程執行可能橫跨許多步驟、耗時很長,Process Manager 必須準備好在某個流程仍在執行時收到新訊息。
為了管理多個平行執行,它為每則進站觸發訊息建立一個新的流程實例(process instance):實例保存該次執行的狀態(當前執行步驟與相關資料),並以唯一的流程識別碼標識。
務必區分兩個概念:
- 流程定義(process definition,或流程樣板)——設計期的構造,定義要執行的步驟順序
- 流程實例(process instance)——某個樣板的一次實際執行
例如同一份流程定義可以有兩個實例:實例 1234 正在執行第 1 步,而實例 5678 正在平行執行第 2 步與第 5 步。
用 Correlation Identifier 對應實例#
因為多個流程實例可能同時執行,Process Manager 必須能把進站訊息關聯到正確的實例。多個實例可能正在執行同一個步驟,所以無法從通道或訊息型別推斷是哪個實例。
這讓我們想起 Correlation Identifier:Process Manager 必須在送給處理單元的訊息中放入一個 Correlation Identifier,而處理單元必須在回覆訊息中把這個識別碼帶回來。

圖 7-21:同一份流程定義的多個流程實例
為什麼前面的模式不用管狀態?#
在傳統的 Pipes and Filters 架構中,是「管道」(也就是 Message Channel)在管理狀態。
若把前面那個流程實作成以通道連接的寫死元件,同樣的狀態就等於:一則識別碼 1234 的訊息躺在等待元件 (1) 處理的通道裡,兩則識別碼 5678 的訊息分別等待元件 (2) 與 (5) 處理。元件 (1) 一消費訊息並完成任務,就把新訊息廣播給元件 (2) 與 (4)——與 Process Manager 的行為完全相同。
值得注意的是:這種訊息流的表示法,與常用來建模 Process Manager 行為的 UML 活動圖極為相似。
這意味著我們可以在設計時用一種抽象表示法為系統行為建模,再決定要用分散式的管道-過濾器架構、還是用中央 Process Manager 的輻輳架構來實作。
一如多數架構決策,「中央 Process Manager vs. 分散式管道-過濾器」不是簡單的是非題。許多情況下,使用多個 Process Manager 元件、各自承載大流程的某一面向,再讓它們透過管道-過濾器架構互相溝通,是最合理的作法。

圖 7-22:把狀態保存在通道中
顯式管理狀態的回報#
在 Process Manager 中顯式管理狀態需要較複雜的元件,但換來強大得多的流程回報能力。
多數 Process Manager 實作能查詢流程實例狀態——於是很容易看出有多少張訂單正等待核可、或因缺貨而被擱置,也能告訴每位客戶他的訂單狀態。若用的是寫死的通道,要取得同樣的資訊就得檢視所有通道。
這個性質不只對回報重要,對除錯也是。用中央 Process Manager 很容易取回流程的當前狀態與相關資料;而對一個完全分散的架構除錯困難得多,若沒有 Message History 或 Message Store 這類機制的協助幾乎不可能。
建立流程定義#
多數商業 EAI 實作都含有 Process Manager 元件,搭配視覺化工具建模流程定義。這些工具多半採用類似 UML 活動圖的表示法,因為兩者語意相當接近,而且活動圖很適合呈現多個平行執行的任務。
過去多數廠商工具把視覺表示法轉成廠商專有的內部流程定義交給引擎執行。但 Web services 的標準化浪潮也沒放過流程定義這一塊,催生了三種「語言」:Microsoft 的 XLANG(由 BizTalk orchestration 建模工具支援)、IBM 的 WSFL(Web Services Flow Language),以及兩家後來合力制定的 BPEL4WS(Business Process Execution Language for Web Services)。
BPEL4WS 是一種以 XML 文件描述流程模型的強大語言,用意是成為建模工具與流程引擎之間的標準化中介語言——讓你能用廠商 X 的產品建模,卻決定在廠商 Y 的引擎上執行。
流程定義的語意可以用相當簡單的詞彙描述。基本構件是活動(activity,有時稱 task 或 action)——它通常能送訊息給另一個元件、等待進站訊息,或在內部執行特定功能(例如 Message Translator)。活動可以串接,也可以用 fork 與 join 平行執行:
| 流程定義的構造 | 管道-過濾器中的對應 |
|---|---|
| fork——讓多個活動同時執行 | Publish-Subscribe Channel |
| join——把多條平行執行緒同步回單一執行緒;所有平行執行緒都完成後才能繼續 | Aggregator |
| branch/決策點——依訊息欄位內容改變執行路徑 | Content-Based Router |
許多建模工具還支援設計迴圈構造,但那其實是 branch 的一個特例。

圖 7-23:UML 活動圖與對應的 Pipes-and-Filters 實作
與其他模式的取捨#
| 分散式 Pipes and Filters | Routing Slip | 中央 Process Manager | |
|---|---|---|---|
| 訊息流複雜度 | 支援複雜流程 | 只支援簡單的線性流程 | 支援複雜流程 |
| 改變流程 | 難改 | 容易改 | 容易改 |
| 單點故障 | 無中央單點故障 | 有(計算路由表處) | 有(Process Manager) |
| 執行期架構 | 高效的分散式架構 | 大致分散 | 輻輳架構可能形成瓶頸 |
| 管理與回報 | 無中央管理與回報點 | 有中央管理點,但無回報 | 中央管理與回報點 |
中央控制與狀態管理,同時也意味著中央單點故障或效能瓶頸。
因此多數 Process Manager 實作允許把流程實例狀態持久化到檔案或資料庫,藉此運用企業級資料庫典型的備援儲存機制。
缺點是:每個處理步驟之後都得把流程實例狀態寫進中央資料庫,這很容易讓資料庫變成新的效能瓶頸。
一如既往,架構師必須在效能、強健性、成本與可維護性之間找到正確的平衡。
範例:Loan Broker 與 BizTalk Orchestration
Loan Broker#
本章末 Loan Broker 範例的 MSMQ 實作實作了一個簡單的 Process Manager——從零打造,自行定義流程管理器與流程實例。同一範例的 TIBCO 實作則使用商業流程管理工具。
Microsoft BizTalk Orchestration Designer#
多數商業 EAI 工具都含有流程設計與執行能力。例如 Microsoft BizTalk 讓使用者透過整合在 Visual Studio .NET 中的 Orchestration Designer 設計流程定義。
一個簡單的編排範例:接收訂單訊息後執行兩個平行活動——一個建立給庫存系統的請求訊息,另一個建立給信用系統的請求訊息;兩個回應都收到後流程才繼續。視覺化表示法讓流程定義很容易跟著讀下去。
