Durable Functions (Azure Functions) 中的工作中樞

Durable Functions 中的工作中樞是儲存體中應用程式目前狀態的表示法,包括所有擱置的工作。 執行函數應用程式時,協調流程、活動和實體函數的進度會持續儲存在工作中樞。 如果因某些原因而暫時停止或中斷後需要重新開機,這麼做可確保應用程式可以在離開時繼續處理。 此外,它可讓函數應用程式動態調整計算背景工作角色。

Diagram showing concept of function app and task hub concept.

就概念而言,工作中樞會儲存下列資訊:

  • 所有協調流程和實體執行個體的執行個體狀態
  • 要處理的訊息,包括
    • 代表正在等待執行之活動的任何活動訊息
    • 正在等候傳遞至執行個體的任何執行個體訊息

活動與執行個體訊息之間的差異在於活動訊息是無狀態的,因此可以在任何地方處理,而執行個體訊息必須傳遞至特定狀態執行個體 (協調流程或實體),且由執行個體識別碼識別。

在內部,每個儲存體提供者均可以使用不同的組織來代表執行個體狀態和訊息。 例如,訊息會由 Azure 儲存體提供者儲存在 Azure 儲存體佇列中,但在 MSSQL 提供者的關聯式資料表中。 這些差異與應用程式的設計無關,但其中一些差異可能會影響效能特性。 我們會在下方的儲存體中的表示法單元中討論這些內容。

工作項目

工作中樞的活動訊息與執行個體訊息代表函數應用程式需要處理的工作。 函數應用程式執行時,它會持續從工作中樞擷取「工作項目」。 每個工作項目均會處理一或多個訊息。 我們會區分兩種類型的工作項目:

  • 活動工作項目:執行活動函數來處理活動訊息。
  • Orchestrator 工作項目:執行協調器或實體函數來處理一或多個執行個體訊息。

背景工作角色可以同時處理多個工作項目,受限於已設定的個別背景工作並行限制

背景工作角色完成工作項目後,即會將效果提交回工作中樞。 這些效果會因所執行的函數類型而有所不同:

  • 已完成的活動函數會建立包含結果的執行個體訊息,並定址至父代協調器執行個體。
  • 已完成的協調器函數會更新協調流程狀態和歷程記錄,而且可能會建立新的訊息。
  • 已完成的實體函數會更新實體狀態,也可以建立新的執行個體訊息。

若為協調流程,每個工作項目都代表該協調流程執行的一。 當協調器要處理新訊息時,即會開始一集。 這類訊息可能表示協調流程應該啟動;或可能表示活動、實體呼叫、計時器或子協調流程已完成;或它可以代表外來事件。 訊息會觸發工作項目,讓協調器能夠處理結果,並繼續下一集。 該集會在協調器完成時結束,或到達必須等候新訊息的點。

執行範例

請考慮一個平行啟動兩個活動的展開傳送/收合傳送協調流程,並等候這兩個活動完成:

[FunctionName("Example")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Task t1 = context.CallActivityAsync<int>("MyActivity", 1);
    Task t2 = context.CallActivityAsync<int>("MyActivity", 2);
    await Task.WhenAll(t1, t2);
}

在用戶端啟動此協調流程後,函數應用程式會將它當做工作項目序列來處理。 每個已完成的工作項目都會在提交時更新工作中樞狀態。 步驟如下:

  1. 用戶端要求使用執行個體識別碼「123」啟動新的協調流程。 用戶端完成此要求後,工作中樞會包含協調流程狀態和執行個體訊息的預留位置:

    workitems-illustration-step-1

    標籤 ExecutionStarted 是許多歷程記錄事件種類的其中一種,可識別參與協調流程歷程記錄的各種訊息和事件種類。

  2. 背景工作角色會執行「協調器工作項目」來處理 ExecutionStarted 訊息。 它會呼叫協調器函數,以開始執行協調流程程式碼。 此程式碼會排程兩個活動,然後在等候結果時停止執行。 背景工作角色認可此工作項目後,工作中樞會包含

    workitems-illustration-step-2

    執行時間狀態現在為 Running,已新增兩個新訊息 TaskScheduled,而歷程記錄現在包含五個事件 OrchestratorStartedExecutionStartedTaskScheduledTaskScheduledOrchestratorCompleted。 這些事件代表此協調流程執行的第一集。

  3. 背景工作角色會執行「活動工作項目」來處理其中一個訊息 TaskScheduled。 它會使用輸入「2」呼叫活動函數。 活動函數完成時,它會建立包含結果的訊息 TaskCompleted。 背景工作角色認可此工作項目後,工作中樞會包含

    workitems-illustration-step-3

  4. 背景工作角色會執行「協調器工作項目」來處理訊息 TaskCompleted。 如果協調流程仍在記憶體中快取,則只能繼續執行。 否則,背景工作角色會先重新執行歷程記錄,以復原協調流程的目前狀態。 然後它會繼續協調流程,傳遞活動結果。 收到此結果後,協調流程仍會等候其他活動的結果,因此會再次停止執行。 背景工作角色認可此工作項目後,工作中樞會包含

    workitems-illustration-step-4

    協調流程歷程記錄現在包含三個以上的事件 OrchestratorStartedTaskCompletedOrchestratorCompleted。 這些事件代表此協調流程執行的第二集。

  5. 背景工作角色會執行「活動工作項目」來處理剩餘的訊息 TaskScheduled。 它會使用輸入「1」呼叫活動函數。 背景工作角色認可此工作項目後,工作中樞會包含

    workitems-illustration-step-5

  6. 背景工作角色會執行另一個「協調器工作項目」來處理訊息 TaskCompleted。 收到第二個結果後,協調流程就會完成。 背景工作角色認可此工作項目後,工作中樞會包含

    workitems-illustration-step-6

    執行時間狀態現在為 Completed,協調流程歷程記錄現在包含四個以上的事件 OrchestratorStartedTaskCompletedExecutionCompletedOrchestratorCompleted。 這些事件代表此協調流程執行的第三集與第四集。

此協調流程執行的最終歷程記錄包含 12 個事件 OrchestratorStartedExecutionStartedTaskScheduledTaskScheduledOrchestratorCompletedOrchestratorStartedTaskCompletedOrchestratorCompletedOrchestratorStartedTaskCompletedExecutionCompletedOrchestratorCompleted

注意

顯示的排程並非唯一的排程:可能有其他不同的可能排程。 例如,如果第二個活動於稍早完成,則單一工作項目可能會處理這兩個執行個體訊息 TaskCompleted。 在此情況下,執行歷程記錄較短,因為只有兩集,而且包含下列 10 個事件:OrchestratorStartedExecutionStartedTaskScheduledTaskScheduledOrchestratorCompletedOrchestratorStartedTaskCompletedTaskCompletedExecutionCompletedOrchestratorCompleted

工作中樞管理

接著,一起進一步了解如何建立或刪除工作中樞、如何在執行多個函數應用程式時正確使用工作中樞,以及如何檢查工作中樞的內容。

建立與刪除

第一次啟動函數應用程式時,會自動在儲存體中建立具有所有必要資源的空白工作中樞。

若您使用預設的 Azure 儲存體提供者,則不需要額外的設定。 或者,請遵循設定儲存體提供者的指示,以確保儲存體提供者可以正確佈建與存取工作中樞所需的儲存體資源。

注意

在停止或刪除函數應用程式時,「不會」自動刪除工作中樞。 若您不想再保留該資料,您必須手動刪除工作中樞、其內容或包含的儲存體帳戶。

提示

在開發案例中,您可能經常需要從乾淨狀態重新開機。 若要快速執行,您可以只變更已設定的工作中樞名稱。 您重新啟動應用程式時,這會強制建立新的空白工作中樞。 請注意,在此案例中不會刪除舊的資料。

多個函數應用程式

如果多個函數應用程式共用儲存體帳戶,則每個函數應用程式必須設有個別的工作中樞名稱。 此需求也適用於預備位置:每個預備位置都必須以唯一的工作中樞名稱進行設定。 單一儲存體帳戶可以包含多個工作中樞。 這項限制在大多數情況下也適用於其他儲存提供者。

下圖說明每個函式應用程式在共用和專用 Azure 儲存體帳戶中的一個工作中樞。

Diagram showing shared and dedicated storage accounts.

注意

工作中樞共用規則的例外狀況,是如果您要為區域災害復原設定應用程式。 如需詳細資訊,請參閱災害復原和異地分佈一文。

內容檢查

有數種常見的方法來檢查工作中樞的內容:

  1. 在函數應用程式中,用戶端物件會提供查詢執行個體儲存的方法。 若要深入了解支援的查詢類型,請參閱執行個體管理一文。
  2. 同理,HTTP API 會提供 REST 要求來查詢協調流程和實體的狀態。 如需詳細資訊,請參閱 HTTP API 參考
  3. Durable Functions 監視器工具可以檢查工作中樞,並提供各種視覺顯示選項。

對於某些儲存體提供者,您也可以直接前往基礎儲存體來檢查工作中樞:

  • 如果使用 Azure 儲存體提供者,執行個體狀態會儲存在執行個體資料表中,以及可使用如 Azure 儲存體總管的工具來檢查歷程記錄資料表
  • 若您使用 MSSQL 儲存提供者,可以使用 SQL 查詢和工具來檢查資料庫內的工作中樞內容。

儲存體中的表示法

每個儲存體提供者均會使用不同的內部組織來代表儲存體中的工作中樞。 了解此組織雖然並非必要,但對函數應用程式進行疑難排解,或嘗試確保效能、可擴縮性或成本目標時可能有所助益。 因此,我們會針對每個儲存體提供者簡短說明資料在儲存體中的組織方式。 如需各種儲存體提供者選項與相互比較方式的詳細資訊,請參閱 Durable Functions 儲存體提供者

Azure 儲存體提供者

Azure 儲存體提供者使用下列元件來代表儲存體中的工作中樞:

  • 兩個 Azure 資料表會儲存執行個體狀態。
  • 一個 Azure 佇列儲存該活動訊息。
  • 一或多個 Azure 佇列會儲存執行個體訊息。 這些所謂的 控制佇列 皆代表根據執行個體識別碼的雜湊,以指派所有執行個體訊息子集的 分割區
  • 租用 blob 和/或大型訊息使用對象的一些額外 blob 容器。

例如,取代PartitionCount = 4命名為xyz的工作中樞包括下列佇列和資料表:

Diagram showing Azure Storage provider storage storage organization for 4 control queues.

接下來,我們更詳細地描述這些元件及其所扮演的角色。

如需 Azure 儲存體提供者如何代表工作中樞的詳細資訊,請參閱 Azure 儲存體提供者文件。

Netherite 儲存體提供者

Netherite 會將所有工作中樞狀態分割成指定的分割區數目。 在儲存體中,會使用下列資源:

  • 包含依分割區分組的所有 Blob 的 Azure 儲存體 Blob 容器。
  • 包含有關資料分割的已發佈計量之 Azure 資料表。
  • 用於在分割區之間傳遞訊息的 Azure 事件中樞命名空間。

例如,在儲存體中使用 PartitionCount = 32 表示的 mytaskhub 的工作中樞,如下所示:

Diagram showing Netherite storage organization for 32 partitions.

注意

所有工作中樞狀態都會儲存在 x-storage Blob 容器。 包含備援資料的資料表 DurableTaskPartitions 與 EventHubs 命名空間:如果遺失其內容,則可以自動復原它們。 因此,不需要設定 Azure 事件中樞命名空間,以保留超過預設到期時間的訊息。

Netherite 會根據記錄與檢查點使用事件來源機制來表示資料分割的目前狀態。 使用區塊 Blob 與分頁 Blob。 您無法直接從儲存體讀取此格式,因此函數應用程式必須在查詢執行個體儲存時執行。

如需 Netherite 儲存體提供者之工作中樞的詳細資訊,請參閱 Netherite 儲存提供者的工作中樞資訊

MSSQL 儲存體提供者

所有工作中樞資料均會使用數個資料表,並儲存在單一關係資料庫中:

  • 資料表 dt.Instances 與資料表 dt.History 會儲存執行個體狀態。
  • 資料表 dt.NewEvents 會儲存執行個體訊息。
  • 資料表 dt.NewTasks 會儲存活動訊息。

Diagram showing MSSQL storage organization.

若要讓多個工作中樞獨立存在於相同的資料庫中,每個資料表都會在其主索引鍵中包含一個資料行 TaskHub。 有別於其他兩個提供者,MSSQL 提供者沒有分割的概念。

如需 Netherite 儲存體提供者之工作中樞的詳細資訊,請參閱 Microsoft SQL (MSSQL) 儲存提供者的工作中樞資訊

工作中樞名稱

由名稱識別的工作中樞必須符合這些規則:

  • 只包含英數字元
  • 以字母開頭
  • 長度下限 3 個字元,長度上限 45 個字元

工作中樞名稱會在 host.json 檔案中宣告,如以下範例所示:

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "MyTaskHub"
    }
  }
}

host.json (Functions 1.x)

{
  "durableTask": {
    "hubName": "MyTaskHub"
  }
}

工作中樞也可以使用應用程式設定來設定,如下列 host.json 範例檔案所示:

host.json (Functions 1.0)

{
  "durableTask": {
    "hubName": "%MyTaskHub%"
  }
}

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "%MyTaskHub%"
    }
  }
}

工作中樞名稱將設定為 MyTaskHub 應用程式設定的值。 下列 local.settings.json 示範如何將 MyTaskHub 設定定義為 samplehubname

{
  "IsEncrypted": false,
  "Values": {
    "MyTaskHub" : "samplehubname"
  }
}

注意

使用部署位置時,最佳做法是使用應用程式設定來設定工作中樞名稱。 如果您想要確保特定位置一律使用特定的工作中樞,請使用「位置黏性」應用程式設定

除了 host.json 之外,也可以在協調流程用戶端繫結中繼資料中設定工作中樞名稱。 如果您需要存取位於不同函式應用程式中的協調流程或實體,那麼這會很有用。 下列程式碼示範如何撰寫使用協調流程用戶端繫結的函式,來處理設定為 [應用程式設定] 的工作中樞:

[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
    [DurableClient(TaskHub = "%MyTaskHub%")] IDurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{
    // Function input comes from the request content.
    object eventData = await req.Content.ReadAsAsync<object>();
    string instanceId = await starter.StartNewAsync(functionName, eventData);

    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

    return starter.CreateCheckStatusResponse(req, instanceId);
}

注意

先前的範例適用於 Durable Functions 2.x。 針對 Durable Functions 1.x,您必須使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 如需版本差異的詳細資訊,請參閱 Durable Functions 版本一文。

注意

僅在您使用一個函數應用程式存取另一個函數應用程式中的協調流程和實體時,才需要在用戶端繫結中繼資料中設定工作中樞名稱。 如果在與協調流程和實體相同的函數應用程式中定義用戶端函式,您應該避免在繫結中繼資料中指定工作中樞名稱。 根據預設,所有用戶端繫結都會從 host.json 設定取得其工作中樞中繼資料。

工作中樞名稱必須以字母開頭,且只包含字母和數字。 如果未指定,則會使用預設的工作中樞名稱,如下表所示:

耐久擴充版本 預設工作中樞名稱
2.x 在 Azure 中部署時,工作中樞名稱是衍生自函數應用程式的名稱。 在 Azure 外部執行時,預設的工作中樞名稱為 TestHubName
1.x 所有環境的預設工作中樞名稱都是 DurableFunctionsHub

如需擴充版本差異的詳細資訊,請參閱 Durable Functions 版本一文。

注意

當共用儲存體帳戶中有多個工作中樞時,可透過名稱來區分各個工作中樞。 如果您有多個函式應用程式共用了共用儲存體帳戶,您必須明確地在 host.json 檔案中為每個工作中樞設定不同的名稱。 否則,多個函數應用程式會彼此競爭接收訊息,這可能會導致未定義的行為,包括協調流程意外「卡在」PendingRunning 狀態。

下一步