incident如何使用Golang構建工作流程引擎?

banq 發表於 2022-09-17
Go

在 incident.io,我們正在開發工具,以幫助人們應對事件,通常是透過自動化其組織的流程。

其中大部分是由我們的工作流程產品提供的,客戶可以用它來實現以下目的。
  • 向執行團隊傳送有關重大事件的最新電子郵件
  • 只要事件是面向客戶的,就上報給客戶成功中心
  • 當一個事件結束時,Slack給領導發資訊,提醒其安排彙報。

工作流作為一個產品功能是非常強大的,我們為它們為客戶提供的價值感到自豪。

然而,在幕後,建立像工作流程這樣的東西可能是困難的。

我們對我們如何建立我們的工作流引擎非常滿意,這篇文章--分為兩部分--分享了我們是如何做到的。

在第一部分中,我們首先解釋了整個功能中使用的核心工作流概念,並檢視了程式碼的結構,以使開發變得簡單。隨後,我們深入探討了我們的工作流生成器(配置UI),展示了這些概念如何在API中暴露出來,並用於支援前端。

第二部分詳細介紹了工作流執行器,展示了我們如何監聽潛在的工作流觸發器,如果條件符合,就執行它們。最後,我們在對專案的評估中反思了我們是否成功地實現了 "放慢速度,加速前進!"的努力。

核心工作流引擎
就其核心而言,工作流程可以被看作是這樣一種實現。

當X發生時,如果Y,做Z

我們的工作流程實現將這一結構分成幾個關鍵概念。

  • "當X發生時 "就是我們所說的觸發器,其中一個觸發器可能是 "一個事件已被建立"
  • "如果Y "是一組條件,適用於與觸發器相關的細節,例如 "嚴重程度>關鍵"。
  • "做Z "是一個步驟列表,例如 "傳送Slack訊息 "或 "升級到PagerDuty"


客戶從我們的儀表板工作流程生成器中配置工作流程,他們在那裡配置觸發器、其條件和任何要執行的步驟。


在高層次上,工作流的實施有兩個方面:
  • 使用資源、條件和工作流程步驟建立工作流程配置
  • 響應觸發器,執行工作流程

這兩方面都有共同的執行元件,但我們將分別解釋每一方面,在我們進行的過程中揭開共同部分。

核心工作流概念
在概述中,我們解釋說,工作流就像計算機程式中的if條件。

我們所建立的工作流引擎和執行器最好正是這樣想的:一種小而簡單的程式語言,定製的目的是。

  • 輕鬆地表示工作流程與之互動的實體(一個事件或Slack頻道)
  • 對這些實體進行靜態分類,以幫助驗證工作流程,並安全地發展其結構
  • 允許反映功能(步驟)和型別(資源),以支援工作流程生成器,它可以被視為工作流程語言的IDE。

這些目標可以從建立一個具有無程式碼前端的靈活的工作流引擎的具體挑戰中得出,我們非常關心人們用我們建立的工作流的穩健性:畢竟,人們關心他們的事件過程是否可靠

在將工作流程比作一種程式語言時,我們引入了一些概念。
  • 資源Resource代表工作流程程式中可用的變數型別
  • 步驟Steps是接收例項化的資源並使用它們執行程式碼的函式。
  • 像許多程式語言一樣,我們有一個scope範圍的概念,它是一個命名的資源例項的集合,我們稱之為 "引用"。
  • 觸發器Trigger,它是可以觸發工作流程的生命週期事件,建立一個範圍,可以根據工作流程的條件進行檢查,並向工作流程的步驟提供資源值

這些概念中的每一個都在我們的後臺實現,並透過HTTP API暴露自己的資訊,工作流生成器使用這些資訊來驅動使用者介面。在程式語言的類比中,你可以把工作流生成器看作是IDE。

程式碼結構
由於我們即將研究如何實現這些概念,因此瞭解後端程式碼的結構是非常有用的。

在可能的情況下,我們按型別(觸發器、步驟、資源)對概念進行分組,其實現不需要知道任何其他型別:例如,任何資源實現都不會處理步驟或觸發器,任何工作流步驟都不會知道觸發器的概念。

這種分離有助於降低開發者常見任務的複雜性(例如,新增工作流步驟、觸發器或資源),因為它不需要與更廣泛的工作流系統互動。相反,開發人員實現了簡單的構件,他們在系統的其他部分註冊,使他們可以使用。

後臺由Go語言編寫,分為幾個包。

  • pkg/engine,它提供了核心型別並實現了條件評估。
  • pkg/engine/resources,工作流可能與之互動的每個實體(Slack頻道、事件、使用者)都必須在這個包內實現engine.Resource介面
  • pkg/workflows,提供一個監聽觸發器並執行工作流的服務
  • pkg/workflows/triggers,所有的觸發器(事件建立、更新等)必須實現一個觸發器介面,並在此包內註冊
  • pkg/workflows/steps,所有的步驟(傳送Slack訊息,升級到PagerDuty等)必須實現一個Step介面並註冊。

包的結構清楚地反映了這種分離,每個 "東西"(無論是觸發器、步驟還是資源)都在該包內的一個檔案中實現。

同樣值得注意的是,我們將工作流程式碼與底層引擎分開。這是因為引擎,包括它的資源和條件評估,並不是針對工作流的。

這種分離有助於澄清每個概念與其他概念的關係,並透過鼓勵明確的界限,使我們能夠在我們的應用程式中重複使用引擎結構,為條件性事件設定或自動存檔事件的規則等提供動力。

詳細點選標題