高效能工作流引擎:DataBuilder與polaris

banq發表於2024-03-05


DataBuilder 框架是一個高階邏輯執行引擎,可用於執行多步驟工作流。該引擎目前為 Flipkart 的結賬系統以及診斷和其他工作流程提供支援。您應該針對以下場景檢視此框架:

  • 多步驟工作流程執行,其中每個步驟都依賴於先前步驟生成的資料
  • 執行可以跨越一個或多個請求範圍
  • 您的系統使用可重複使用的元件,這些元件可以以不同的方式組合以生成不同的最終結果

上述的幾個例子是:
  • 類似結帳的系統,使用者可以在多個步驟中提供全部或僅部分資料,並根據訂單可能完成或將控制權返回給使用者。隨著使用者填寫更多詳細資訊,系統會更接近目標,最終在使用者提供所有詳細資訊後生成訂單。
  • API 閘道器結合多個來源的資料以生成最終響應

以下是顯著特徵:
  • 為構建者提供基於註釋的後設資料處理
  • 資料流分析器和構建器根據提供的後設資料和目標動態生成執行圖
  • 支援在一個執行範圍的上下文中有意義的迴圈和瞬態資料
  • 單執行緒和多執行緒資料流執行器
  • 極低的開銷(單執行緒執行器為 20 usec)
  • 公開低階和高階 API,用於動態註冊構建器和目標以及構建流程
  • 大量測試用例,涵蓋框架的各個方面,可供參考

該框架可以以兩種模式使用:
  • 請求範圍內的流
  • 跨多個請求的流程

1、請求範圍內的基本流程如下:

  • 識別和建立資料類
  • 建立構建器
  • 註冊構建器後設資料(消耗、產生)
  • 構建(並可選擇儲存)指定目標資料的資料流
  • 開始接受請求
    • 建立資料流例項
    • 接受資料增量中的輸入資料
    • 使用增量執行資料流
    • 此時可能會發生以下兩種情況之一:
      • 給出並生成所有所需資料並生成目標資料
      • 所有必需的資料不存在並且流程未完成
    • 在上述兩種情況下,都會返回當前流程執行期間生成的所有資料的對映
    • 所有非瞬態資料都新增到資料流例項中存在的資料集中
    • 可以在後續的執行呼叫中提供更多資料來完成流程
    • 執行器使用資料增量和資料集中存在的資料來生成更多資料併到達生成指定目標資料的最終狀態

2、跨多個請求執行流程
在這種情況下,執行更加複雜,如下所示:

  • 為使用者活動上下文建立 DataFlowInstance。例如,這代表結帳會話。
    • 對於跨流更改的事務性,每個 DataFlowInstance 應包含其自己的 DataFlow 副本
  • 每次呼叫執行器時,都需要將 DataFlowInstance 與一組輸入資料一起傳入
  • 新的輸入資料(也稱為增量)被新增到考慮執行此執行的資料集中
  • 系統開始執行並儘可能地繼續執行流程
  • 每執行一步,新生成的資料都會新增到活動資料集中
  • 如果構建器的輸入不足以生成資料,則它可能會選擇返回 null
  • 如果流程中未達到最終狀態,系統會再次從頭開始迴圈,使用 DataSet,現在會使用先前執行生成的資料進行擴充
  • 系統在以下情況下停止:
    • 流的目標資料已生成
    • 迭代中沒有生成新資料
  • 增強資料集儲存在例項中。不新增瞬態資料

示例:多步結賬

<font>//Step 1:登入和地址<i>
response = executor.run(instance, userDetails);
//Step 2: 購物車詳情和編輯<i>
response = executor.run(instance, cart);
//Step 3: 支付<i>
response = executor.run(instance, payment);
//Done<i>


相關:
polaris是Golang 的高效能工作流程編排器,靈感來自DataBuilder

用例

  1. 您具有多步驟工作流執行,其中每個步驟都依賴於先前步驟生成的資料。
  2. 執行可以跨越一個請求範圍或多個範圍。
  3. 您的系統使用可重複使用的元件,這些元件可以以不同的方式組合以生成不同的最終結果。
  4. 您的工作流程可以暫停、恢復,甚至從頭開始。

侷限性

  1. 工作流版本控制實施起來很棘手:
    1. 除非您能夠承受 100% 的停機時間,確保所有活動工作流程進入最終狀態,否則部署新程式碼需要確保向後相容性。
    2. 這意味著 - 您需要部署一個向後相容較舊的非終端工作流程的程式碼版本,而較新的工作流程將在新程式碼上執行。
    3. 一旦舊的工作流程完成,就需要進行部署來清理過時的程式碼。
  2. 與 Cadence、Conductor 相比,該框架的抽象級別較低:[list=1]
  3. 如果有外部(可靠)服務為每個工作流 ID 提供回撥,則可以使工作流忽略故障。
  4. 可以透過新增自定義程式碼以透過偵聽器推送事件來設定檢測。
<ul>


用法

<font>// dataStore = DataStore{} - use your database by implementing the IDataStore interface<i>
polaris.InitRegistry(dataStore)
polaris.RegisterWorkflow(workflowKey, workflow)

executor := polaris.Executor{
    Before: func(builder reflect.Type, delta []IData) {
        fmt.Printf(
"Builder %s is about to be run with new data %v\n", builder, delta)
    }
    After: func(builder reflect.Type, produced IData) {
        fmt.Printf(
"Builder %s produced %s\n", builder, produced)
    }
}

response, err := executor.Run(workflowKey, workflowId, dataDelta)

 

相關文章