(轉)在Windows workflow 裏實現人工活動

在Windows workflow 裏實現人工活動

作者 Boris Lublinsky譯者 張善友 發佈於 2008年6月16日 上午3時29分

社區
Architecture,
.NET,
SOA
主題
工作流/業務流程管理
標籤
WWF

雖然Windows workflow是實施業務流程處理的一個優秀框架,但它卻缺乏對人工活動的直接支持。 微軟雖然發佈了 [12]幾種方法來解決這個問題,但這些方法卻顯得不夠通用。本文將定義一種完全通用的方法,在WF中實現對人工活動的支持。

支持人工交互的複雜性帶來衆多的挑戰,如下所列,可見一斑:

  • 用戶的響應時間(用戶活動的執行時間)是不可預知的。
  • 當請求發生的時候用戶可以不連接到系統,因此需要存儲請求,並當用戶登錄到系統之時提交給用戶。
  • 在不同的機器上可以有多個同時運行的工作流程。但是用戶通常需要一個所有任務的統一視圖。

業界已經認識到了這些問題,並制定了兩個主要的規格來解決這些問題 [34]。我們將根據以下思想來構建人工活動的實現,而不是紙面上的規格說明書。

一個解決方案的組件視圖

整體解決方案的主要組件如圖1所示。

圖1 解決方案組件

解決方案的核心是一個工作隊列管理器。這是一個集中的服務,負責跟蹤系統所有用戶的所有任務。任何需要人工交互活動的工作流程(或者服務/應用程序所包含的工作流程),都去調用一個自定義的工作流活動[5],以通過它將請求提交到工作隊列管理器,並對其進行持久化,同時允許系統的其他組件與這些請求一同協作。這樣,工作隊列管理器就成爲了工作流引擎和人工活動執行之間的解耦層。在工作流執行期間,如果用戶並不存在於系統中,這種方法同樣提供了支持。同時,工作隊列管理器通過形成的集中服務,可以將所有任務與指定的用戶結合,而不用考慮是從哪裏初始化的流程。因爲不同的用戶任務可以要求不同的輸入信息以及產生不同的輸出,工作流和人工活動之間的通信採用了XML進行輸入輸出,從而可以處理任何可能的請求和響應。雖然使用XML似乎會增加實現上的複雜度,但.NET對XML序列化的良好支持,使得XML和對象之間的映射易如反掌。工作隊列查看器是一個GUI應用程序,允許用戶直觀地查看輸入的已經準備就緒的所有任務。該應用程序是通用的,僅僅顯示了任務的基本要素,包括名稱,類型,優先級,創建者等等。根據隊列中的這些信息,用戶可以決定執行某一項特定的任務。任務的實際處理過程是通過一個在功能上支持給定任務的任務應用程序來完成的。一個工作流隊列管理應用程序提供了一個用戶界面,用來支持對工作隊列管理器的管理。它可以查看和修改現有的人工任務,查看它們的歷史記錄等。最後,一個人工活動就是一個自定義活動(參看邊欄“Windows Workflow Foundation 組件模型”,它實現了與任務隊列管理器的通信,併爲工作流開發人員展現了一個非常簡單的針對人工任務執行的編程模型。從人工交互的角度來看,這與常規的服務調用並無二致。

Windows Workflow Foundation 組件模型 正如[11]所描述的,Windows Workflow Foundation (WWF)的實現不同於當下主流工作流實現的可執行工作流語言(域語言)。在WWF中,“過程圖中的活動關聯了一個實現該活動運行時行爲的組件,組件由一種通用編程語言實現。過程語言中的每一個活動都對應一個實現組件。例如,一個Web服務調用活動,一個人工任務活動或一個電子郵件活動都對應一個實現組件 ”。 因此,我們能夠非常容易地通過引入新的活動類型擴展WWF,以實現特定情況下的(在我們的案例中,就是人工任務的活動)運行時行爲,通過實現新的活動這種方法,使得構建或者擴展現有的過程語言非常簡單。

組件之間的整體交互如序列圖所示(圖2)

圖2 序列圖

我們可以看到,上面的整體解決方案裏包含兩種類型的組件:

  • 通用的,包括人工活動,工作隊列管理器和工作隊列查看器。這些組件運行於人工任務的“標準”特性(attributes )之上,並將任務的輸入輸出視爲通用的XML。
  • 特殊的,包括工作流本身和處理業務流程的應用程序,實現了特定業務對象的XML序列化/反序列化,並使用這些對象實現他們的功能。

本文只討論通用組件的解決方案。

工作隊列管理器

服務接口和功能

正如我們在前面所定義的那樣,工作隊列管理器是一個集中的服務。它的功能基於數據契約,如圖3所示。

圖3 工作隊列管理器數據契約

這個數據模型的主要組件包括:

  • 人工任務 - 這個數據類型定義的主要元素是一個人工任務(參見注釋[3]),包括:
    • TaskID ── 一項任務的唯一標識
    • Task Name ── 一項可讀的標識性任務名稱(非唯一的)
    • Task status ── 任務狀態。任務可能的狀態都定義在枚舉 TaskStatusEnum中,數據可以是: Ready, Reserved 和completed。一個簡化的任務狀態遷移圖如圖4所示。

      圖4 任務狀態遷移圖

      當任務提交到工作隊列管理器中時,它的狀態是Ready。一旦應用將請求提交,狀態就遷移到Ready狀態,而在應用程序處理完任務之後,任務狀態則遷移到completed狀態,它標誌着工作隊列管理器將任務完成的響應信息返回給人工活動。如果任務被取消或者超時,任務則退回到Ready狀態。
    • 任務的優先級可以在創建任務的時候分配給一個任務,用於表示任務的重要性。 工作隊列查看器根據任務的優先級展現任務,因爲高優先級的任務會放到隊列的頂部。
    • CreatedOn 和createdBy 屬性指定任務的創建時間戳和任務的創建人。它們用來描述隊列中任務的處理順序。
    • Task type 是任務的類型,用於選擇適合的處理任務的業務處理程序。目前我們是使用流程/任務的名稱相結合的方式(任務類型的數據元素)。將任務類型與相關的數據類型分開,簡化了切換到另一種定義任務類型定義的方式(如有需要)。
    • ReservedBy,ReservedOn 用於鎖定並確保一次只能有一個用戶處理一項任務。
    • CompletedBy 和 CompletedOn 元素不影響任務的處理,更多地是用來登記,以保證服務可以用於對應用的維護以及/或者報告。
    • Potential Owners 允許列表中的用戶可以查看/處理這個任務。目前,一個可能的用戶可以被定義爲一個特定用戶或者用戶組 (用戶數據類型)
    • Escalations 用於標示一項任務的升級清單。每次升級(升級數據類型)可以被定位爲notification(notification數據類型) 或者reassignment (reassignment 數據類型)。這兩種類型的升級在其中一個升級應用後會包含一個超時 (超時來自於任務的創建),郵件 (通知,notification) 和一個新的用戶名單(再分配,(reassignment )。目前的實現不支持升級。
    • Escalated flag 標示任務是否已經升級。
    • Task request 和 reply 字段包含任務請求和應答的字符串版本。
  • CallbackInfo是人工活動用來指定工作隊列管理器所需的特定信息的數據類型,工作隊列管理器發送一個回覆給人工活動,以標誌任務執行完成。該類型包括類別、名字以及包含了工作隊列管理器進程的消費者類型的服務版本 [10]。實施取決於服務所註冊的解決該信息的實際端點地址、綁定和綁定參數。
  • WorkflowParameters 數據類型是用於指明將回復傳遞到對應工作流實例的適當位置。它包含了工作流實例ID (確定工作流實例) 以及一個關聯關係(確定工作流步驟/活動)(因爲自定義人工活動是基於工作流隊列,所以我們當前用工作流隊列的名字作爲一個關聯)。
  • HumanTaskView是一個具體的人工任務子集數據類型,用於爲任務隊列查看器返回任務信息。
  • WorkItemQuery數據類型被任務隊列查看應用程序用作有關當前任務的請求信息。
  • MaintenanceQuery數據類型被維護應用程序用於查詢和查看人工任務。

除了數據類型,數據模型還定義了故障數據類型,參見圖5。

圖 5 故障數據類型

工作隊列管理器公開了三組服務──工作流服務,用戶服務和維護服務。

工作流服務節(圖6)定義了一個服務,人工任務活動可以利用它爲一個執行提交一個任務,同時還定義了一個工作流服務公開的接口,該接口被工作隊列管理器用來標識執行完成。這兩個服務提供了人工活動之間的集成,並運行在工作流和工作隊列管理器中。

圖 6 工作流服務

提交給由工作隊列管理器實現的執行服務,從作爲不同工作流其中一部分的人工活動處接收請求。一旦接收到請求,就會存儲到數據庫裏做進一步的處理。

completeExecution契約雖然在此處定義,但卻是在工作流中實現的。這個服務用於通知工作流一個特定任務的執行已經完成,工作流可以執行了。

用戶服務(圖7)用於支持用戶與工作隊列管理器之間的交互。WorkWithItems 服務支持三種操作:

  • 工作隊列查看器使用GetItemsList方法爲給定用戶返回'Ready'狀態的任務列表(可以選擇一個給定的類型)。
  • 業務應用程序使用WorkWithItem 方法獲取它要處理的任務的完整信息。這裏會對用戶憑證(credentials )和任務的潛在所有者列表進行比較,如果用戶不屬於該組,就會拋出一個未經授權的異常。一旦業務應用程序開始處理一項任務,則該請求還會觸發任務狀態的改變,修改Reserved和reservedOn以及reservedby字段,這些字段會被填充爲適當的信息。這是一種簡單的預定(鎖)機制,能夠確保在某個特定時間只有一個操作任務的用戶。如果一個業務應用程序試圖訪問已被預定的任務,操作將引發一個錯誤,表明這個任務正在被另一個用戶處理(錯誤提供了用戶的信息和他/她開始處理任務的時間)。爲了避免任務無限期的鎖定,服務是一個超時鎖,如果接收一個請求到處於Reserved狀態的任務清單或者工作項的時間超過30分鐘,任務狀態將修改爲Ready。
  • 業務應用程序使用CompleteExecution 方法通知工作隊列管理器任務處理完成,業務應用程序返回完成狀態,完成狀態可以是completed或aborted。如果返回的狀態是 Completed,任務的執行狀態就修改爲Completed,並且服務會通知人工活動任務完成。如果返回的狀態是aborted,任務的狀態就修改爲 Ready。

圖 7 用戶服務

維護服務(圖8)用於支持工作隊列管理器的維護應用程序。

圖8 維護服務

查看任務方法使用MaintenanceQuery 數據類型定義的過濾器返回現有任務的一個列表。在看到任務之後,這些任務可以被修改和改變,可以通過更新任務方法將任務返回給工作隊列管理器。

底層數據庫和數據訪問

服務的數據庫設計(圖9)包含表,以及用於持久化與人工任務相關的所有信息的必要內容。主表爲人工任務表,包含了所有人工任務的基本信息,包括任務名稱,ID(由服務分配),優先級和任務生命週期事件,以及規定執行事件的主體和時間的補充信息。

圖 9 工作隊列管理器數據庫

額外的表包含任務的額外信息,包括:

  • Callback和TaskCallback表。Callback表包含了服務的信息,它由一個工作流程實現並負責監聽從人工任務管理器傳來的請求。表的設計依賴於服務註冊的方法,因此它使用了服務的名稱和版本來充分解析服務的終結點地址和綁定信息。多個人工任務可以使用相同的回調服務,這就是爲什麼我們把它放在一張單表中的原因。TaskCallback表是HumanTask和Callback表的連接表。
  • TaskType 和 TaskTaskType 表。TaskType表包含任務的類型信息。因爲我們擁有相同類型的多個人工任務,我們將該信息分離到各自的表中。TaskTaskType是HumanTask表和TaskType表的連接表。
  • WorkflowReference 表包含的信息是連接人工任務到工作流的特定實例/活動。它包含工作流實例ID和實例所使用的工作流隊列的名稱(見下文)。因爲這一機制在將來可能發生變更,我們把它的信息分離到它自己的一張表中。人工任務和工作流引用之間總是一對一關係,因此不需要使用連接表,我們使用外鍵連接 WorkflowReference表和HumanTask表。
  • PotentialUser 和TaskPotentialUser。每個任務都有一個潛在用戶清單,而在系統中的每個用戶都有一個有權操作的任務的清單。因此我們用 PotentialUser信息來跟蹤用戶,用連接表TaskPotentialUser 連接用戶到任務。
  • Notification, Reassignment, TaskNotification, TaskReassignment 和ReassignmentPotentialUser 表。這些在實現升級的時候用來支持升級。

爲了優化數據的訪問,我們還實現了幾個存儲過程和視圖。存儲過程是:

  • AddTaskCallback 存儲過程能夠添加回調信息和分配人工任務(使用下面的InsertTaskCallback存儲過程)。它首先檢查是否已經有回調存在,如果存在則使用存在的回調記錄,否則在Callback表中創建一個回調記錄,然後調用InsertTaskCallback 存儲過程創建一個連接。
  • InsertTaskCallback存儲過程用於生成TaskCallback表,這樣就能夠創建給定回調與人工任務之間的關係。
  • AddTaskType存儲過程用於添加任務類型信息和關聯它與給定人工任務的關係(使用下面的InsertTaskTypeTask存儲過程)。它首先檢查是否已經存在任務類型,如果存在則使用存在的任務類型記錄,否則在TaskType表中創建一條新的記錄,然後調用InsertTaskTypeTask創建一個連接。
  • InsertTaskTypeTask存儲過程用於生成TaskTaskType表,這樣就能夠創建給定任務類型和人工任務之間的關係。
  • AddTaskPotentialOwner 存儲過程負責添加潛在用戶信息,以及將用戶信息與給定的人工任務建立關聯(使用下面的InsertTaskPotentialUser存儲過程)。它首先檢查是否存在一個潛在的用戶,如果存在則使用已經存在的用戶記錄,否則在PotentialUser表中創建一條記錄,然後調用InsertTaskPotentialUser創建一個連接。
  • InsertTaskPotentialUser存儲過程用於生成TaskPotentialUser表,這樣就能夠創建用戶和人工任務之間的關係。

使用這些存儲過程通過兩方面的因素減少了數據庫的訪問次數,同時通過消除重複數據以減少數據庫的數據量。

數據庫視圖(圖10)簡化了數據庫數據的讀取。分配給用戶的所有任務信息(包括任務類型)可以從單個視圖獲得。

圖 10 完成任務視圖

持久層類圖實現了倉儲模式(repository pattern),參見圖11。

圖 11 持久層類圖

服務實現

服務的整體實現非常直接。一旦某個特定方法被調用了,它就會執行委派給實現了所有必須的數據庫訪問的倉儲類(圖11)。

人工活動

人工活動是一個實現了人工交互的自定義工作流活動。這個活動隱藏了工作流設計器與工作隊列管理器的通信,並允許象調用普通服務那樣處理用戶交互。

這個活動的實現基於工作流隊列[7] 提供的活動同外部交互的異步通信:活動註冊到隊列的接受消息中,服務則通過隊列發送消息。一個自定義活動可以使用這個模型處理外部事件以及與異步活動執行完成的通信。它允許一個活動執行到一個點,然後等待觸發使得它可以繼續執行。這種實現的整體交互參見圖12。

圖12 使用工作流隊列實現活動

一旦啓動,只要允許,活動執行就會繼續。隨着到達需要外部執行的活動點,活動就會註冊到工作流隊列中。然後工作流實例進入等待狀態,並可能會被鈍化(持久化)。一旦外部執行完畢,它就會將信息壓入到隊列中。此時,運行時就可以重新激活工作流,繼續執行。

人工活動的實際實現包含兩部分──活動本身和一個回調服務。

一個人工活動發送一個消息到人工任務管理器去啓動一個新的人工任務開始處理。如果該服務的調用是成功的,活動會將自身註冊到工作流隊列中,並進入等待狀態。如果執行服務出現任何錯誤,活動會拋出一個工作流故障,它能夠被工作流處理。

當服務接收到答覆時,它會將回復消息壓入活動的工作隊列中。隊列消息喚醒一個活動,彈出回覆消息並完成它的執行。

回調服務實現完成執行契約(圖6),同時必須被一個實現了工作流的服務/應用程序所啓動。爲了使服務正確工作,WorkflowRuntime必須被設置,可以使用executionComplete類的一個公共靜態變量來實現。

人工活動的執行需要幾個參數 - 任務類型,優先級等等。這些參數被定義爲DependencyProperty[8]。暴露的DependencyProperty 可以被工作流設計器設置 [9],從而使得設置活動參數可視化,而無需編程(參見圖13)。

圖13 配置活動參數

工作隊列查看器

一個工作隊列查看器是作爲一個用戶控件(圖14)實現的,可以將它放到任一表單中。該控件使用了一個dataview控件,並接收一個委託作爲參數。當行的任意單元格被點擊,委託就會傳遞一個任務ID和任務類型而被調用。圖14顯示了一個簡單的委託,彈出一個消息框。

圖 14 工作隊列查看器

結論

儘管推動了業務流程的完全自動化,但人工活動依舊不可或缺,並仍然會在業務流程實現上繼續扮演着重要的角色。正如我們在文章前言一開始所定義的那樣,引入用戶的交互會帶來許多額外的關注點,這些關注點與工作流的實現沒有直接的關係。本文介紹的徹底解耦的實現方法,能夠將工作流開發與用戶交互開發之間的關注點進行分離。此外,在人工任務管理器中對人工任務支持的集中化減少了對給定用戶的任務管理的聚合。

致謝

非常感謝 Paul Rovkah 和 Rob Sheldon 爲本文提供的幫助。

參考資源

1 Jeremy Boyd. Integrating Windows Workflow Foundation and Windows Communication Foundation. MSDN January 2007. 2 Windows Workflow Foundation Web Workflow Approvals Starter Kit?. Microsoft Downloads. 3 Web Services Human Task (WS_HumanTask). 4 WS BPEL extensions for People. 5 Matt Milner. Build Custom Activities To Extend The Reach Of Your Workflows MSDN Magazine, December 2006, 6 Dare Obasanjo XML Serialization in the .NET Framework. January 2003, 7 Serge Luca. Using the Windows Workflow Foundation Queuing system. 8 Glenn Block Attached Properties and the Workflow Designer. 9 Dennis Pilarinos. Getting DependencyProperty RegisterAttached properties to appear in the Property Browser redux. 10 B.Lublinsky, Implementing a Service Registry for .NET Web Services. January 2008, InfoQ, 11 Tom Baeyens. Process Component Models: The Next Generation In Workflow? February 2008, InfoQ.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章