Timer in Durable Functions (Azure Functions)
Durable Functions bieten permanente Timer für die Verwendung in Orchestratorfunktionen zum Implementieren von Verzögerungen oder zum Einrichten von Timeouts für asynchrone Aktionen. Dauerhafte Timer sollten in Orchestratorfunktionen anstelle der „sleep“- oder „delay“-APIs verwendet werden, die möglicherweise in die Sprache integriert sind.
Dauerhafte Timer sind Aufgaben, die mithilfe der entsprechenden „create timer“-API für die bereitgestellte Programmiersprache erstellt werden (wie unten dargestellt) und entweder eine Fälligkeitszeit oder eine Dauer als Argument akzeptieren.
// Put the orchestrator to sleep for 72 hours
DateTime dueTime = context.CurrentUtcDateTime.AddHours(72);
await context.CreateTimer(dueTime, CancellationToken.None);
Wenn Sie die Zeitgeberaufgabe erwarten, wartet die Orchestratorfunktion bis zur angegebenen Ablaufzeit.
Hinweis
Die Orchestrierungen verarbeiten weiterhin andere eingehende Ereignisse, während sie auf das Ablaufen einer Timeraufgabe warten.
Timereinschränkungen
Wenn Sie einen Timer erstellen, der um 16:30 Uhr UTC abläuft, stellt das zugrunde liegende Durable Task-Framework eine Nachricht in die Warteschlange, die erst um 16:30 Uhr UTC sichtbar wird. Wenn die Funktions-App in der Zwischenzeit auf null Instanzen herunterskaliert wird, stellt die neue sichtbare Timernachricht sicher, dass die Funktions-App erneut auf einer geeigneten VM aktiviert wird.
Hinweis
- Für JavaScript-, Python- und PowerShell-Apps sind dauerhafte Timer auf sechs Tage beschränkt. Um diese Einschränkung zu umgehen, können Sie die Timer-APIs in einer
while
-Schleife verwenden, um eine längere Verzögerung zu simulieren. Aktuelle .NET- und Java-Apps unterstützen beliebig lange Timer. - Je nach Version des verwendeten SDK und Speicheranbieters können lange Timer von sechs Tagen oder mehr intern mithilfe einer Reihe kürzerer Timer (z. B. mit einer Dauer von drei Tagen) implementiert werden, bis die gewünschte Ablaufzeit erreicht wird. Dies kann im zugrunde liegenden Datenspeicher beobachtet werden, wirkt sich jedoch nicht auf das Orchestrierungsverhalten aus.
- Verwenden Sie keine integrierten Datums- oder Uhrzeit-APIs zum Abrufen der aktuellen Uhrzeit. Wenn Sie ein Ablaufdatum für einen Timer in der Zukunft berechnen, verwenden Sie immer die aktuelle time-API der Orchestratorfunktion. Weitere Informationen finden Sie im Artikel Codeeinschränkungen für Orchestratorfunktionen.
Verwendung für Verzögerung
Das folgende Beispiel veranschaulicht, wie Sie permanente Timer für die Ausführungsverzögerung verwenden. Im Beispiel wird 10 Tage lang täglich eine Abrechnungsbenachrichtigung ausgegeben.
[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");
}
}
Hinweis
Die vorherigen C#-Beispiele gelten für Durable Functions 2.x. Für Durable Functions 1.x müssen Sie DurableOrchestrationContext
anstelle von IDurableOrchestrationContext
verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions-Versionen.
Warnung
Vermeiden Sie Endlosschleifen in Orchestratorfunktionen. Informationen zum sicheren und effizienten Implementieren von Endlosschleifenszenarien finden Sie unter Eternal orchestrations in Durable Functions (Azure Functions) (Ewige Orchestrierungen in Durable Functions [Azure Functions]).
Verwendung für das Timeout
In diesem Beispiel wird veranschaulicht, wie mit permanenten Timern Timeouts implementiert werden.
[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;
}
}
}
Hinweis
Die vorherigen C#-Beispiele gelten für Durable Functions 2.x. Für Durable Functions 1.x müssen Sie DurableOrchestrationContext
anstelle von IDurableOrchestrationContext
verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions-Versionen.
Warnung
In .NET, JavaScript, Python und PowerShell müssen Sie alle erstellten dauerhaften Timer abbrechen, wenn Ihr Code nicht auf ihren Abschluss wartet. Informationen dazu, wie Sie ausstehende Timer abbrechen, finden Sie in den Beispielen oben. Das Durable Task-Framework ändert den Status einer Orchestrierung nicht in „Abgeschlossen“, solange nicht alle ausstehenden Aufgaben (einschließlich solcher mit dauerhaften Timern) abgeschlossen oder abgebrochen werden.
Dieser Abbruchmechanismus mit when-any-Muster beendet nicht die Ausführung von laufenden Aktivitätsfunktionen oder untergeordneten Orchestrierungen. Stattdessen lässt er zu, dass die Orchestratorfunktion das Ergebnis ignoriert und fortfährt. Wenn Ihre Funktions-App den Verbrauchstarif verwendet, wird Ihnen weiterhin jeglicher Zeit- und Arbeitsspeicherverbrauch der abgebrochenen Aktivitätsfunktion in Rechnung gestellt. Standardmäßig gilt für Funktionen, die im Rahmen des Verbrauchstarifs ausgeführt werden, ein Timeout von fünf Minuten. Wenn dieses Limit überschritten wird, wird der Azure Functions-Host neu gestartet, um jegliche Ausführung zu beenden und eine unkontrollierte Abrechnungssituation zu verhindern. Der Funktionstimeout ist konfigurierbar.
Ein ausführlicheres Beispiel zum Implementieren von Timeouts in Orchestratorfunktionen finden Sie im Artikel Human interaction and Timeouts – Phone Verification (Menschliche Interaktion und Timeouts – Telefonüberprüfung).