Durable Functions (Azure Functions) 中的計時器
在此文章
Durable Functions 提供「永久性計時器」 ,用於協調器函式中實作延遲,或在非同步動作上設定逾時。 永久性計時器應該用於協調器函式,而不是可能內建於語言中的「睡眠」或「延遲」API。
永久性計時器是針對所提供語言使用適當的「建立計時器」API 所建立的工作,如下所示,並以到期時間或持續時間作為引數。
// 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)
# Put the orchestrator to sleep for 72 hours
$duration = New-TimeSpan -Hours 72
Start-DurableTimer -Duration $duration
// Put the orchestrator to sleep for 72 hours
ctx.createTimer(Duration.ofHours(72)).await();
當您「等候」計時器工作時,協調器函式會進入睡眠,直到指定的到期時間為止。
注意
協調流程會在等候計時器工作到期時,繼續處理其他傳入事件。
計時器限制
當您建立一個在 UTC 下午 4:30 過期的計時器時,基礎「永久性工作架構」會將訊息加入佇列,而此訊息只在 UTC 下午 4:30 出現。 如果在此期間,函數應用程式縮小為零個執行個體,則可見的新計時器訊息可確保函數應用程式會在合適的 VM 上再次啟動。
注意
若是 JavaScript、Python 和 PowerShell 應用程式,永久性計時器的限制為六天。 若要因應這項限制,您可以使用 while
迴圈中的計時器 API 來模擬較長的延遲。 最新的 .NET 和 JAVA 應用程式支援沒有長度限制的計時器。
視所使用的 SDK 版本和儲存體提供者 ,6 天以上的長時間計時器可能是使用一連串較短的計時器 (例如持續時間為 3 天的計時器) 直到達到所需的到期時間,以此方式在內部實作而成。 這可以在基礎資料存放區中觀察到,但不影響協調流程行為。
請勿使用內建的日期/時間 API 來取得目前時間。 計算計時器到期的未來日期時,請一律使用協調器函式的目前時間 API。 如需詳細資訊,請參閱協調器函數程式碼條件約束 一文。
延遲的使用方式
下列範例說明如何使用永久性計時器來延遲執行。 此範例會每天發出帳單通知 10 天。
[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 df = require("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)
param($Context)
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;
}
else
{
// timeout case
return false;
}
}
}
注意
先前的 C# 範例是針對 Durable Functions 2.x。 針對 Durable Functions 1.x,您必須使用 DurableOrchestrationContext
而不是 IDurableOrchestrationContext
。 如需版本差異的詳細資訊,請參閱 Durable Functions 版本 一文。
const df = require("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;
}
else
{
// 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)
param($Context)
$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 主機會重新開機來停止所有執行,以避免計費失控狀況發生。 函式逾時可設定 。
如需如何在協調器函數中實作逾時的更深入範例,請參閱人為互動和逾時 - 電話驗證 一文。
下一步