Durable Functions 提供「永久性計時器」 ,用於協調器函式中實作延遲,或在非同步動作上設定逾時。 永久性計時器應該用於協調器函式,而不是可能內建於語言中的「睡眠」或「延遲」API。

永久性計時器是針對所提供語言使用適當的「建立計時器」API 所建立的工作,如下所示,並以到期時間或持續時間作為引數。

JavaScript Python PowerShell
// Put the orchestrator to sleep for 72 hours
DateTime dueTime = context.CurrentUtcDateTime.AddHours(72);
await context.CreateTimer(dueTime, CancellationToken.None);
// Put the orchestrator to sleep for 72 hours
// Note that DateTime comes from the "luxon" module
const deadline = DateTime.fromJSDate(context.df.currentUtcDateTime, {zone: 'utc'}).plus({ hours: 72 });
yield context.df.createTimer(deadline.toJSDate());
# Put the orchestrator to sleep for 72 hours
due_time = context.current_utc_datetime + timedelta(hours=72)
durable_timeout_task = context.create_timer(due_time)

計時器限制

當您建立一個在 UTC 下午 4:30 過期的計時器時,基礎「永久性工作架構」會將訊息加入佇列,而此訊息只在 UTC 下午 4:30 出現。 如果在此期間,函數應用程式縮小為零個執行個體,則可見的新計時器訊息可確保函數應用程式會在合適的 VM 上再次啟動。

  • 若是 JavaScript、Python 和 PowerShell 應用程式,永久性計時器的限制為六天。 若要因應這項限制,您可以使用 while 迴圈中的計時器 API 來模擬較長的延遲。 最新的 .NET 和 JAVA 應用程式支援沒有長度限制的計時器。
  • 視所使用的 SDK 版本和儲存體提供者,6 天以上的長時間計時器可能是使用一連串較短的計時器 (例如持續時間為 3 天的計時器) 直到達到所需的到期時間,以此方式在內部實作而成。 這可以在基礎資料存放區中觀察到,但不影響協調流程行為。
  • 請勿使用內建的日期/時間 API 來取得目前時間。 計算計時器到期的未來日期時,請一律使用協調器函式的目前時間 API。 如需詳細資訊,請參閱協調器函數程式碼條件約束一文。
  • 延遲的使用方式

    下列範例說明如何使用永久性計時器來延遲執行。 此範例會每天發出帳單通知 10 天。

    JavaScript Python PowerShell
    [FunctionName("BillingIssuer")]
    public static async Task Run(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
        for (int i = 0; i < 10; i++)
            DateTime deadline = context.CurrentUtcDateTime.Add(TimeSpan.FromDays(1));
            await context.CreateTimer(deadline, CancellationToken.None);
            await context.CallActivityAsync("SendBillingEvent");
    

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

    const { DateTime } = require("luxon"); module.exports = df.orchestrator(function*(context) { for (let i = 0; i < 10; i++) { const deadline = DateTime.fromJSDate(context.df.currentUtcDateTime, {zone: 'utc'}).plus({ days: 1 }); yield context.df.createTimer(deadline.toJSDate()); yield context.df.callActivity("SendBillingEvent");
    import azure.functions as func
    import azure.durable_functions as df
    from datetime import datetime, timedelta
    def orchestrator_function(context: df.DurableOrchestrationContext):
        for i in range(0, 9):
            deadline = context.current_utc_datetime + timedelta(days=1)
            yield context.create_timer(deadline)
            yield context.call_activity("SendBillingEvent")
    main = df.Orchestrator.create(orchestrator_function)
    for ($num = 0 ; $num -le 9 ; $num++){    
        $expiryTime =  New-TimeSpan -Days 1
        $timerTask = Start-DurableTimer -Duration $expiryTime
        Invoke-DurableActivity -FunctionName 'SendBillingEvent'
    
    @FunctionName("BillingIssuer")
    public String billingIssuer(
            @DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
        for (int i = 0; i < 10; i++) {
            ctx.createTimer(Duration.ofDays(1)).await();
            ctx.callActivity("SendBillingEvent").await();
        return "done";
    
    [FunctionName("TryGetQuote")]
    public static async Task<bool> Run(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
        TimeSpan timeout = TimeSpan.FromSeconds(30);
        DateTime deadline = context.CurrentUtcDateTime.Add(timeout);
        using (var cts = new CancellationTokenSource())
            Task activityTask = context.CallActivityAsync("GetQuote");
            Task timeoutTask = context.CreateTimer(deadline, cts.Token);
            Task winner = await Task.WhenAny(activityTask, timeoutTask);
            if (winner == activityTask)
                // success case
                cts.Cancel();
                return true;
                // timeout case
                return false;
    

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

    const { DateTime } = require("luxon"); module.exports = df.orchestrator(function*(context) { const deadline = DateTime.fromJSDate(context.df.currentUtcDateTime, {zone: 'utc'}).plus({ seconds: 30 }); const activityTask = context.df.callActivity("GetQuote"); const timeoutTask = context.df.createTimer(deadline.toJSDate()); const winner = yield context.df.Task.any([activityTask, timeoutTask]); if (winner === activityTask) { // success case timeoutTask.cancel(); return true; // timeout case return false;
    import azure.functions as func
    import azure.durable_functions as df
    from datetime import datetime, timedelta
    def orchestrator_function(context: df.DurableOrchestrationContext):
        deadline = context.current_utc_datetime + timedelta(seconds=30)
        activity_task = context.call_activity("GetQuote")
        timeout_task = context.create_timer(deadline)
        winner = yield context.task_any([activity_task, timeout_task])
        if winner == activity_task:
            timeout_task.cancel()
            return True
        elif winner == timeout_task:
            return False
    main = df.Orchestrator.create(orchestrator_function)
    $expiryTime =  New-TimeSpan -Seconds 30
    $activityTask = Invoke-DurableActivity -FunctionName 'GetQuote'-NoWait
    $timerTask = Start-DurableTimer -Duration $expiryTime -NoWait
    $winner = Wait-DurableTask -Task @($activityTask, $timerTask) -Any
    if ($winner -eq $activityTask) {
        Stop-DurableTimerTask -Task $timerTask
        return $True
    else {
        return $False
    
    @FunctionName("TryGetQuote")
    public boolean tryGetQuote(
            @DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
        Task<Double> activityTask = ctx.callActivity("GetQuote", Double.class);
        Task<Void> timerTask = ctx.createTimer(Duration.ofSeconds(30));
        Task<?> winner = ctx.anyOf(activityTask, timerTask);
        if (winner == activityTask) {
            // success case
            return true;
        } else {
            // timeout case
            return false;
    

    在 .NET、JavaScript、Python 和 PowerShell 中,如果您的程式碼不會等待計時器完成,則您必須取消任何建立的永久性計時器。 如需如何取消暫止計時器,請參閱上述範例。 等到所有未完成的工作 (包含永久性計時器工作) 都完成或取消之後,「永久性工作架構」才會將協調流程的狀態變更為「已完成」。

    這個使用 when-any 模式的取消機制不會終止進行中的活動函式或子協調流程執行。 只是讓協調器函式略過結果並繼續執行。 如果函數應用程式使用取用量方案,您仍然要為已放棄的活動函數所耗用的任何時間和記憶體付費。 根據預設,在取用量方案中執行的函式會在五分鐘後逾時。 如果超過此限制,Azure Functions 主機會重新開機來停止所有執行,以避免計費失控狀況發生。 函式逾時可設定

    如需如何在協調器函數中實作逾時的更深入範例,請參閱人為互動和逾時 - 電話驗證一文。

    了解如何引發和處理外部事件