<style> .red { color: red; } </style> # formflow系統架構說明文件 ###### tags: `凌群內部文件` ## Outline: 1. **系統簡介** 2. **資料庫架構** 3. **流程運作架構** 4. **通知的事件狀態** ## 系統簡介: #### 此系統為表單流程系統,可開立表單並且搭配自定義流程執行運作。 #### 原先規劃應為獨立存在,但現行架構因與apis核心系統業務邏輯上有大量耦合,因此已成為apis核心的子系統,不可獨立運作。 #### 在理解此系統前,應先了解apis核心系統有所謂的<span class="red">服務目錄</span>(ServiceCategory)和<span class="red">服務請求</span>(WorkOrder,以下皆簡稱工單),同時會搭配一張表單,若該表單有流程,則送出工單後會依照流程開始執行,後續會在流程運作有更詳細的介紹。 #### 每一張表單底下都還可以有子表單。 #### 此系統所有跟人員有關的id,全部都是對應到該使用者cmdb的id,並非apis核心的userId,請特別注意apis核心在塞使用者id的時候,請拿CiObject.id塞進去才是正確的! #### 2022/1/21 新增根據不同流程狀況,通知要有不同的event_code ## 資料庫架構 #### 最為核心的物件共有5個,分別為<span class="red">表單主檔(form_template)、表單格式(form_format)、表單資料(form_data)、流程主檔(workflow_template)、流程執行實體(execution_process)</span> #### 建立表單時,必須先建立起表單主檔,單一主檔下可建立多個表單格式,等於可以有多個版本格式可挑選,每個版本都有單一且唯一的流程主檔搭配,並且底下可擁有多筆表單資料 #### 但請注意,雖然在"服務請求"上將apis核心和formflow系統連結在一起的是<span class="red">表單資料id(form_data.id),而非表單主檔id(form_template_id)</span>,但整個系統主要核心都建立在表單主檔身上,如下圖。![](https://i.imgur.com/fVvZTVx.jpg) #### 接下來將逐一大致介紹每張表的用途: * form_template: 表單主檔,以系統角度來看,此為搭配apis核心的服務目錄(service_category)而存在,但其實本身也可以單獨存在,並非一定要綁定服務目錄。 * service_category_link_form_template: apis核心服務目錄和表單主檔的對照表,apis核心在建立服務目錄時,都一定要綁定一個,也是唯一一個表單主檔。但其實嚴格來說,應該由核心來管理服務目錄和表單主檔的對照關係才對,但當時與合作廠商欠缺溝通,核心系統在設計系統架構時,並無考慮到formflow子系統的部分,導致不得不把這對照關係放在formflow系統管理...不然子系統根本就沒service_category相關的資料表,不是很合理。 * form_template_mapping_child: 表單主檔的母子表單對照關係表,在系統上我們可以在服務目錄總管設定母表單主檔底下要有哪些子表單主檔。在新增子表單資料時,會先需要子表單主檔為依據,才有辦法新增子表單資料。 * form_format: 表單格式,記錄此表單拉了哪些欄位,位子在哪裡等等資訊。表單主檔與表單格式關係為一對多,由於可多版本存在,會記錄著哪一個格式為最新格式,也會記錄該格式目前是草稿或發布。 * form_data: 表單資料,目前是綁定要跟工單搭配才有意義,記錄著每個表單元件填寫的值,採用json格式紀錄,流程運作有很大一部分取決於表單內容的值。 * form_data_mapping_child: 母子表單資料對照表,由於可以有子表單的關係,但無論是母表單資料還是子表單資料,都是form_data的一部分,只有透過此對照表才能知道母子表單資料的對照關係,非常重要。 * workflow_template: 流程主檔,跟表單格式的對照關係為一對一,每一個版本只會有一個流程主檔,並且乘載著流程所有的資訊,包含節點、每個節點的通知等等,全部都是跟流程主檔綁定在一起。 * execution_process: 流程執行實體,此為流程真正在runtime執行時的物件,因此當程式開始運行時,會記錄目前走到哪個節點。若流程執行有問題,通常要來看這張表。流程主檔跟執行實體關係為一對多,並且一個表單運作時,只會有唯一一個實體。以例子來說,表單格式+流程主檔就像地圖,流程執行實體就只是在地圖上行走的棋子,並在規劃好的路線上行走;表單資料就像財產,經過不同地區,會有不同變化,每個棋子也只會有一份財產。<span class="red">注意,當流程走到最終節點時,是會消失的,只會留下曾執行過的紀錄。</span> 流程執行狀態(workflow_life_state)如下: * 0: 未執行 * 1: 執行中 * 2: 條件沒過,暫停中 * 3: 已編輯,再度執行中(重新啟動流程時會將狀態改成3) * 4: 已結束過的節點重新執行,並等待重新提交中 * 5: 手動停用 * 6: 等待服務目錄管理員指派中 * 99: 流程異常(目前尚未用到) * execution_process_history: 流程執行實體歷史資料,每經過一個節點,就會有一筆資料,但每一個實體所經歷過的節點只會有一筆資料,若該實體走回曾經過的節點,並不會新增,而是會更新原本的歷史紀錄。此外,若流程執行實體已經走到終點,將會消除連結的execution_process_id,但本身紀錄不會消除。 流程執行歷史狀態如下: * 0: 已結束 * 1: 執行中 * 2: 初始執行後,條件沒過,暫停中 * 3: 已編輯,再度執行中(重新啟動流程時會將狀態改成3) * 4: 已結束過的節點重新執行,並等待重新提交中 * 5: 手動停用 * 6: 等待服務目錄管理員指派中 * 7: 已編輯提交,但條件依然沒過 * 99: 流程異常(目前尚未用到) * node: 流程節點,以下將逐一介紹較為重要的欄位: - 節點類型(type): 分為起始(start)、人工(manual)、自動(auto)、結束(end) - 指派方式(dispatch_type): 會記錄該節點的指派方式,有以下三種: - 0: 給工單發起人 - 1: 給指定的某人 - 2: 通知服務目錄管理員(dispatcher) - 服務目錄管理員id(dispatcher_id): 每個服務目錄會綁定表單主檔及格式,因此只要是同一個流程內的全部節點,都會是相同的服務目錄管理員(有時看到註解寫系統管理員是相同一件事,原本叫系統管理員,後來改名為服務目錄管理員)。 - 負責人id(assignee_id): 每個節點都會有自己的負責人,<span class="red">但這邊只是預設值,並非真正實體執行時的負責人!</span> - 最大可執行次數(max_execution_times): 超過最大可執行次數時會發送通知給服務目錄管理員。 - 節點有效時間(lead_time_seconds): 單位為秒,有效時間計算方式為節點開始時間到現在時間的秒數是否>有效時間秒數。 - 小鈴鐺開始時間的資料來源型態(schedule_start_date_field_type): 小鈴鐺設定時間的資料來源型態,可分為直接設定或者從表單欄位來。 - 小鈴鐺開始時間的欄位值(schedule_start_date_field_value): 小鈴鐺開始的預定日期。 - 小鈴鐺提前提醒時間(advance_notify_time_seconds): 在小鈴鐺開始的預定日期提前多久提醒,必須把預定日期扣掉提醒時間,才是真正發通知的時間。 - 是否為sla節點(is_sla): 未來用來判斷該節點要不要列入sla計算的依據,目前尚未真的用到 * link: 節點與節點之間的連結線,記錄著前一個節點和下一個節點id,還有連結線上會有conditions,用來判斷是否要流入下一個節點 * dynamic_assignment: 節點動態指派表,流程實體執行時,真正runtimes時該節點的負責人,這邊才是真的工單運作中,記錄著該由誰負責。流程啟動最一開始會從節點根據指派方式,先把初始設定值複製到這邊來處理,只要在運作中修改指派人,通通是來改這張表,一樣當流程實體結束時,會一併消失。 * dynamic_bell_config: 動態小鈴鐺設定表,一樣流程最一開始時會從節點根據資料來源型態(schedule_start_date_field_type)來決定是直接抓值還是從表單抓值過來,原先有需求說即便在流程運作過程中,也要可以動態設定時間,因此才有這張表,但目前前後端都並無此相關設定,若未來有需要,可在WorkflowController再開一隻api專門設定小鈴鐺動態的值。 * field_permission: 表單欄位呈現的權限 * notification_config: 通知設定,包含要通知給誰和通知內容,值得一提的是原本發送通知是由formflow發送,後來與apis核心整合過程,改將發送通知部分轉交核心轉發,並且搭配freemaker模板語言撰寫通知內容,節點這邊的通知內容只是提供模板部分抽換部分字詞的功能。此外,通知者的部分可以用","串聯多個CiId,達到同時發送多人的目的。 * variables: 動態變數輸出,每個節點都可以設定自定義的變數輸出,用來乘載自動節點執行完節點動作後,解析response的結果後將其存成一個變數,提供後續其他節點使用。 * alter_field: 更改表單欄位值,分為進入節點前更改(value_in)和離開節點後更改(value_out),此設定值會直接不管使用者填入了什麼值,直接套用此設定的值。舉例: 若有設定進入節點前某個欄位值為123,那麼不管使用者原本此欄位到底寫了什麼值,一進入到這個節點後,都會被固定為123,離開節點後更改也是相同概念。 * action: 自動節點專有的執行節點動作,原先規畫可執行打api或執行cmd line指令等等,但目前實作只有打api,並且要搭配action_detail才有完整的涵義 * action_detail: 執行節點動作細節,目前拆分為parameter和value的部分,parameter可根據不同的script去自由定義,目前根據api的行為有以下參數: - parameter: - method: 打api的方式,有get、post等等 - url: 要打api的路徑 - body: 要打的參數 - inputVariables: 可帶入api的參數 ## 流程運作架構 1. loadWorkflow: 讀取executionProcess以及相關workflow資料 2. 檢查流程是否需要被中斷刪除 3. 檢查是否被手動停用 4. 當前節點的執行次數+1 5. 通知apis核心api更新工單狀態 6. 若有設定小鈴鐺提醒功能,一樣需要加入監控小鈴鐺是否到了提醒時間,並且只有第一次通過的時候才加入小鈴鐺監控 7. 預防使用者造成無限迴圈的狀況,需判定該節點是否超過最大執行次數 8. 如果是簽核節點,執行動作前要先檢查動態指派表內是否已經有被指派人(assignee),如果沒有就終止 9. 發送通知給assignee和onEntry裡面的人 10. 執行節點動作,進入節點時有以下兩個動作 - 1. 對表單資料進行操作 - 2. 執行script 打api動作 11. findNextNode: 尋找下一個節點 12. 更新節點狀態,若有下一個節點則繼續執行 ![](https://i.imgur.com/sUGtTOQ.jpg) ## 通知的事件狀態 根據不同的情境,event_code如下,但自動執行節點動作失敗原本就並沒有通知的需求,因此先從缺: | 節點類型 | 作業指派方式(dispatch_type) | 通知時機 | 通知對象 | Event_Code | Event_Name | Emoji | 備註 | |:--------:|:-----------------------:|:-----------:|:-------------------------:|:----------------:|:------------:|:-----:|:---:| | 人工作業 | 請求單建立人、預設指派 | 首次進入節點 | 當前節點負責人、其他通知指定人 | TaskNotify | 請求單作業通知 | 📑 | | | | | 超時 | 當前節點負責人、服務目錄管理員 | OverTimeNotify | 作業超時警告 | ⏲ | | | | | 超過次數 | 服務目錄管理員 | OverCountNotify | 作業迴圈警告 | 🔁 | | | | 服務目錄管理員指派 | 首次進入節點 | 服務目錄管理員 | WaitAssignNotify | 待指派作業通知 | 🗣 | | | | | 超時 | 當前節點負責人、服務目錄管理員 | OverTimeNotify | 作業超時警告 | ⏲ | | | | | 超過次數 | 服務目錄管理員 | OverCountNotify | 作業迴圈警告 | 🔁 | | | | | 修改指派人 | 新的被指派人 | AssigneeNotify | 受派作業提醒 | 🙋 | | | 自動執行 | |執行節點動作失敗| 服務目錄管理員 | AutoTaskError |自動執行作業失敗 | 🛑 |未來再說| | | | 超時 | 服務目錄管理員 | OverTimeNotify | 作業超時警告 | ⏲ | | | | | 超過次數 | 服務目錄管理員 | OverCountNotify | 作業迴圈警告 | 🔁 | | 小鈴鐺提醒: | 通知時機 | 通知對象 | Event_Code | Event_Name | Emoji | |:---------------:|:------------------:|:----------:|:-----------:|:-----:| | 有設定小鈴鐺通知時 | 小鈴鐺設定的通知人清單 | BellNotify | 請求單設定提醒 | 🔔 |