工作流程執行模式

在 .NET 中執行工作流程時, 執行模式 控制超步驟的處理方式及事件如何傳遞給消費者。 該 InProcessExecution 類別提供兩種執行模式: OffThreadLockstep

概觀

OffThread(預設) 步調一致
超步驟執行 背景討論串 消費者討論串
事件傳遞 事件發生即時處理 每當一個超步驟完成後,會進行一次批次處理
步驟執行 獨立於事件處理 暫停直到批次事件被消耗
並行 使用者在超步驟執行期間讀取事件 消費者與超階執行交替
適用對象 即時串流與製作場景 測試、除錯、確定性排序

脫離主線程

OffThread 是 預設 的執行模式。 超步執行於背景執行緒,事件在觸發後會立即透過通道實作進行串流。

// OffThread is the default — these are equivalent:
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);
await using StreamingRun run = await InProcessExecution.OffThread.RunStreamingAsync(workflow, input);

運作方式

  1. 背景任務在訊息待處理時持續執行超步驟。
  2. 當執行者產生輸出或事件時,所得的 WorkflowEvent 物件會寫入無界限的 Channel<WorkflowEvent>中。
  3. 消費者透過 WatchStreamAsync 從頻道讀取事件,並即時接收它們。
  4. 當所有超步驟完成且無訊息剩餘時,執行會以 Idle or PendingRequests 狀態停止。

由於超步驟迴圈與消費者迴圈同時執行,事件一被引發便立即出現——沒有緩衝延遲。 這使得 OffThread 非常適合需要低延遲事件傳遞的串流場景,例如在使用者介面中顯示逐個標記更新。

同時運行

OffThread 也支援一種 並行 變體,允許多個執行同時共享同一工作流程實例:

await using StreamingRun run = await InProcessExecution.Concurrent.RunStreamingAsync(workflow, input);

這很重要

同時執行要求工作流程中的所有執行器都必須在建構子上宣告 crossRunShareable ,或以工廠方法形式提供。

步調一致

在 Lockstep 模式下,超步驟會執行在 消費者的執行緒 中,而非背景任務。 事件會在每個超步驟中累積,並在超步驟完成後以批次形式發出。

await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);

運作方式

  1. 消費者呼叫 WatchStreamAsync,驅動執行迴圈。
  2. 超級步驟執行至完成,事件會累積在佇列中。
  3. 超級步驟結束後,所有排隊事件都會交給消費者。
  4. 下一個超步驟只有在消費者收到前一步驟的所有事件後才開始。

這種交替模式意味著消費者與工作流程引擎從不會同時運作。 事件傳遞是確定性的——所有來自超步驟的事件都保證會先於下一個超步驟的任何事件抵達。

何時使用 Lockstep

Lockstep 在以下情況下非常有用:

  • 測試 — 確定性事件排序使斷言變得簡單明瞭。
  • 除錯 — 當執行過程停留在使用者執行緒上時,逐步除錯會更容易。
  • 有序處理 ——需要在下一個超級步驟開始前,先完整處理一個超步驟的事件的情境。

選擇執行模式

大多數生產情境的建議是使用預設 OffThread 模式。 它提供最佳的響應速度,並允許工作流程在消費者處理事件時持續處理。

當確定性行為比效能更重要時,例如單元測試或除錯工作階段,請使用 Lockstep

// Production: OffThread (default)
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);

// Testing: Lockstep for deterministic behavior
await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);

非串流執行

兩種執行模式都支援非串流執行,這可以透過 RunAsync 來實現。 在非串流模式下,工作流程會持續執行,並將所有事件收集到物件中 Run ,而非逐步串流:

Run run = await InProcessExecution.RunAsync(workflow, input);

// Access all emitted events
foreach (WorkflowEvent evt in run.OutgoingEvents)
{
    // Process events
}

由於非串流執行會在事件完成後收集所有事件,因此 OffThread 的即時事件傳遞優勢不適用。 非串流情境中模式的主要差異在於 執行緒:OffThread 會在背景執行緒執行超級步驟,釋放呼叫執行緒並等待完成;而 Lockstep 則在呼叫者執行緒上執行超級步驟,阻塞執行緒直到工作流程結束。

非串流執行則使用預設的 OffThread 模式。 在不流式執行環境下運用 Lockstep:

Run run = await InProcessExecution.Lockstep.RunAsync(workflow, input);

下一步

執行模式不適用於 Python 工作流程。 Python 工作流程使用單一執行模型,透過非同步產生器處理超步驟處理與事件傳遞。 此模型類似於 .NET Lockstep 模式——除非消費者主動從產生器拉取事件,否則步驟不會推進。

關於執行 Python 工作流程的資訊,請參見 工作流程建構器與執行

在 Go 中執行工作流程時,執行環境控制超步驟的處理方式及事件如何傳遞給消費者。 該workflow/inproc封裝暴露三個環境:Default/OffThread、、 LockstepConcurrent和 。

概觀

離線討論串 / 預設 步調一致 並發
超步驟執行 背景 goroutine 由事件消費者驅動 背景 goroutine
事件傳遞 事件發生即時處理 在讀取串流的同時分批處理 事件發生即時處理
適用對象 即時串流與製作場景 測試、除錯、確定性排序 具有並行安全綁定的共享工作流程實例

脫離主線程

OffThread 是預設的執行模式。 這兩者是等價的:

stream, err := inproc.Default.RunStreaming(ctx, wf, input)
stream, err := inproc.OffThread.RunStreaming(ctx, wf, input)

運作方式

  1. 背景 goroutine 會在有訊息待處理時執行超步驟。
  2. 當執行者產生輸出或事件時,工作流程事件會寫入串流。
  3. 消費者使用 WatchStream 讀取事件,並在事件產生時接收它們。
  4. 當所有超步驟完成且無訊息時,執行會停止並顯示閒置或待處理請求狀態。

同時運行

當工作流程中所有執行者綁定都支援並行共享執行時,請使用 inproc.Concurrent

stream, err := inproc.Concurrent.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

步調一致

在 Lockstep 模式下,工作流程的執行會隨著取用端從串流中讀取資料而推進。 這使得事件排序在測試和除錯時具有確定性。

stream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

for evt, err := range stream.WatchStream(ctx) {
    if err != nil {
        return err
    }
    // inspect event
}

運作方式

  1. 消費者呼叫 WatchStream,驅動執行迴圈。
  2. 超級步驟會執行至完成,並累積事件。
  3. 累積的事件會傳回給消費者。
  4. 下一個超級步驟只有在消費者收到前一個超級步驟的事件後才開始。

何時使用 Lockstep

當確定性行為比低延遲串流更重要時,例如在單元測試、除錯,或是您想在下一個超級步驟開始之前,先完全處理完一個超級步驟的事件等情境中,請使用 Lockstep。

選擇執行模式

在大多數生產情境下,請使用 inproc.Defaultinproc.OffThread。 當確定性事件排序比串流延遲更重要時,例如測試中,才會使用 inproc.Lockstep 。 只有在工作流程中每個綁定都支援並行共享執行時才使用 inproc.Concurrent

// Production: OffThread (default)
stream, err := inproc.Default.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

// Testing: Lockstep for deterministic behavior
testStream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer testStream.Close(ctx)

非串流執行

所有執行環境也支援非串流(non-stream Run),該執行會持續到下一次停止,並在回傳執行時儲存所發出的事件。

run, err := inproc.Default.Run(ctx, wf, input)
if err != nil {
    return err
}

for evt := range run.NewEvents() {
    if output, ok := evt.(workflow.OutputEvent); ok {
        fmt.Printf("Final result: %v\n", output.Output)
    }
}

下一步