這很重要
對於進程模型的支援將於 2026 年 11 月 10 日結束。 我們強烈建議您遷移應用程式至隔離工作模式以獲得完整支援。
永續協調流程是會無限期執行的協調器函數,並使用 continue-as-new API 定期重設自己的歷程記錄。 它們對聚合器、定期背景工作,以及任何需要無限迴圈且沒有無限歷史成長的 Durable Functions情境都很有用。
若沒有 continue-as-new,一個無限循環的編排器會隨著每個排程任務累積編 排歷史 ,最終導致效能問題和過度記憶體使用。 永恆編排模式透過重置每次迭代的歷史來解決此問題。
備註
Eternal orchestration 程式碼範例可用於 C#、JavaScript、Python 和 Java。 PowerShell 不支援 continue-as-new。
本文內容:
- continue-as-new 的運作方式 — 重設機制
- 考量事項 — 例外行為、未完成任務及外部事件
- 週期性工作範例 — 避免計時器重疊的清理迴路
- 啟動永續協調流程 — 啟動和單一執行個體模式
- 結束永續協調流程 — 正常停止和終止
永恆編排 指的是透過 continue-as-new API 定期重置自身歷史,以持續運行的編排。 它們對聚合器、定期背景工作,以及任何需要無限循環且沒有無限歷史成長的情境都很有用。
若沒有 continue-as-new,一個無限循環的編排會隨著每個排程任務累積歷史,最終導致效能問題及過度記憶體使用。 永恆編排模式透過重置每次迭代的歷史來解決此問題。
這很重要
目前,PowerShell Durable Task SDK 尚未提供。
本文內容:
- continue-as-new 的運作方式 — 重設機制
- 考量事項 — 例外行為、未完成任務及外部事件
- 週期性工作範例 — 避免計時器重疊的清理迴路
- 啟動永續協調流程 — 啟動和單一執行個體模式
- 結束永續協調流程 — 正常停止和終止
continue-as-new 的運作方式
協調器函式會呼叫continue-as-new的 方法來重設其狀態,而不會使用無限迴圈。 此方法會取一個可序列化的 JSON 參數,該參數成為下一代 Orchestrator 函式產生的新輸入。
當您呼叫 continue-as-new 時,協調流程執行個體會使用新的輸入值重新啟動自身。 同一個實例 ID 會被保留,但 orchestrator 函式的歷史會被重置。
編排不使用無限迴圈,而是透過在編排上下文中呼叫 continue-as-new 方法來重置狀態。 此方法會取一個可序列化的 JSON 參數,該參數成為下一代編排產生的新輸入。
當您呼叫 continue-as-new 時,協調流程執行個體會使用新的輸入值重新啟動自身。 相同的實例 ID 會被保留,但編排的歷史會被重置。
永恆編排考量因素
在協調流程中使用 continue-as-new 方法時,請留意下列注意事項:
當使用此
continue-as-new方法重置編排器函式時,Durable Task Framework 會保留相同的實例 ID,但會內部建立並使用新的 執行 ID。 這個執行 ID 不會對外公開,但在除錯編排執行時非常有用。當執行期間發生未處理的例外狀況時,協調流程會進入 失敗 狀態,而且執行會終止。 從
continue-as-new區塊呼叫finally,不會在未攔截的例外狀況之後重新啟動協調流程。當編排呼叫
continue-as-new時,任何未完成任務的結果都會被丟棄。 例如,如果已排程計時器,且在計時器觸發前呼叫continue-as-new,則該計時器事件會遭到捨棄。您可以選擇在
continue-as-new重新啟動之間,保留未處理的外部事件。 在 C# 中,預設ContinueAsNew保留未處理的事件。 在Java中,continueAsNew預設也會保留事件。 在Python中,continue_as_new除非save_events=True,否則不會保留事件。 在 JavaScript 中,continueAsNew需要一個saveEvents參數(true或false)來控制此行為。
在協調流程中使用 continue-as-new 方法時,請留意下列注意事項:
當透過此
continue-as-new方法重置編排時,持久任務 SDK 會維持相同的實例 ID,但內部會建立並使用新的 執行 ID 。 此執行識別碼不會在外部公開,但在偵錯協調流程執行時可能很有用。當執行期間發生未處理的例外狀況時,協調流程會進入 失敗 狀態,而且執行會終止。 從
continue-as-new區塊呼叫finally,不會在未攔截的例外狀況之後重新啟動協調流程。當編排呼叫
continue-as-new時,任何未完成任務的結果都會被丟棄。 例如,如果已排程計時器,且在計時器觸發前呼叫continue-as-new,則該計時器事件會遭到捨棄。您可以選擇在
continue-as-new重新啟動之間,保留未處理的外部事件。 在.NET和Java中,continue-as-new預設保留未處理的事件。 在Python中,continue_as_new除非save_events=True,否則不會保留事件。 在 JavaScript 中,continueAsNew需要一個saveEvents參數(true或false)來控制此行為。 在所有情況下,當編排下一次呼叫waitForExternalEvent或wait_for_external_event時,未處理的事件都會被傳送。
定期工作範例
永續協調流程的一個常見使用案例是定期背景工作,例如清除作業。
為什麼不使用計時器觸發器? 基於 CRON 的計時器觸發器會在固定時間運行,無論前一次執行是否結束。 永續協調流程會等候工作完成後,才排程下一次反覆項目,因此執行作業絕不會重疊。
| Approach | 排程 (間隔 1 小時,30 分鐘作業) | 重疊風險 |
|---|---|---|
| 計時器觸發器(CRON) | 1:00, 2:00, 3:00 | 是的——如果工作超過了時間範圍 |
| 永恆的管弦樂編排 | 1:00, 2:30, 4:00 | 否 — 下一次執行會等候完成 |
孤立工人模型
[Function("Periodic_Cleanup_Loop")]
public static async Task Run(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
await context.CallActivityAsync("DoCleanup");
// sleep for one hour between cleanups
DateTime nextCleanup = context.CurrentUtcDateTime.AddHours(1);
await context.CreateTimer(nextCleanup, CancellationToken.None);
context.ContinueAsNew(null);
}
進行中模型
[FunctionName("Periodic_Cleanup_Loop")]
public static async Task Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
await context.CallActivityAsync("DoCleanup", null);
// sleep for one hour between cleanups
DateTime nextCleanup = context.CurrentUtcDateTime.AddHours(1);
await context.CreateTimer(nextCleanup, CancellationToken.None);
context.ContinueAsNew(null);
}
public class PeriodicCleanupLoop : TaskOrchestrator<object?, object?>
{
public override async Task<object?> RunAsync(TaskOrchestrationContext context, object? input)
{
await context.CallActivityAsync("DoCleanup");
// sleep for one hour between cleanups
await context.CreateTimer(TimeSpan.FromHours(1), CancellationToken.None);
context.ContinueAsNew(null);
return null;
}
}
開啟一場永恆的協奏
使用 start-new 或 schedule-new 永續性客戶端方法來啟動持續編排,就像其他編排功能一樣。 為了確保一次只執行一個實例,請使用固定實例 ID。 欲了解更多資訊,請參見單調管配器。
孤立工人模型
[Function("Trigger_Eternal_Orchestration")]
public static async Task<HttpResponseData> OrchestrationTrigger(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData request,
[DurableClient] DurableTaskClient client)
{
string instanceId = "StaticId";
await client.ScheduleNewOrchestrationInstanceAsync(
"Periodic_Cleanup_Loop",
null,
new StartOrchestrationOptions { InstanceId = instanceId });
return await client.CreateCheckStatusResponseAsync(request, instanceId);
}
進行中模型
[FunctionName("Trigger_Eternal_Orchestration")]
public static async Task<HttpResponseMessage> OrchestrationTrigger(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage request,
[DurableClient] IDurableOrchestrationClient client)
{
string instanceId = "StaticId";
await client.StartNewAsync("Periodic_Cleanup_Loop", instanceId);
return client.CreateCheckStatusResponse(request, instanceId);
}
使用 schedule-new 客戶端方法開始永久編排,就像其他編排一樣。 為了確保一次只執行一個實例,請使用固定實例 ID。 欲了解更多資訊,請參見單調管配器。
string instanceId = "StaticId";
await client.ScheduleNewOrchestrationInstanceAsync(
"PeriodicCleanupLoop",
null,
new StartOrchestrationOptions { InstanceId = instanceId });
從永久協調流程離開
如果編排器函式最終需要完成,不要呼叫 continue-as-new 讓函式退出。
如果協調器函式處於無限迴圈中,且需要停止,請使用協調流程用戶端繫結的終止 API 來停止它。
孤立工人模型
await client.TerminateInstanceAsync(instanceId, "Cleanup no longer needed");
進行中模型
await client.TerminateAsync(instanceId, "Cleanup no longer needed");
欲了解更多資訊,請參閱 實例管理。
如果協調流程最終需要完成,請不要呼叫 continue-as-new,讓協調流程結束即可。
如果編排處於無限迴圈且需要停止,請使用持久任務用戶端的 終止 API 來停止它。
await client.TerminateInstanceAsync(instanceId, "Cleanup no longer needed");