Funktionsverkettung in Durable Functions – „Hello Sequence“-Beispiel
Artikel
Bei der Funktionsverkettung geht es um das Muster für die Ausführung einer Funktionssequenz in einer bestimmten Reihenfolge. Häufig muss die Ausgabe einer Funktion auf die Eingabe einer anderen Funktion angewendet werden. Dieser Artikel beschreibt die Verkettungssequenz, die Sie beim Durcharbeiten des Durable Functions-Schnellstarts (C#, JavaScript, TypeScript, Python, PowerShell oder Java) erstellen. Weitere Informationen zu Durable Functions finden Sie unter Übersicht zu Durable Functions.
Version 4 des Node.js-Programmiermodells für Azure Functions ist allgemein verfügbar. Das neue v4-Modell ist für eine flexiblere und intuitivere Benutzeroberfläche für JavaScript- und TypeScript-Entwickler konzipiert. Weitere Informationen zu den Unterschieden zwischen v3 und v4 finden Sie im Migrationshandbuch.
In den folgenden Codeschnipseln steht JavaScript (PM4) für das Programmiermodell V4, die neue Erfahrung.
Die Funktionen
In diesem Artikel werden die folgenden Funktionen in der Beispiel-App beschrieben:
E1_HelloSequence: Eine Orchestratorfunktion, die E1_SayHello mehrmals hintereinander aufruft. Die Ausgaben der E1_SayHello-Aufrufe werden gespeichert, und die Ergebnisse werden aufgezeichnet.
E1_SayHello: Eine Aktivitätsfunktion, die einer Zeichenfolge das Wort „Hello“ voranstellt.
HttpStart: Eine durch HTTP ausgelöste Durable Client-Funktion, mit der eine Instanz der Orchestrierung gestartet wird.
Alle C#-Orchestrierungsfunktionen müssen über einen Parameter vom Typ DurableOrchestrationContext verfügen, der in der Assembly Microsoft.Azure.WebJobs.Extensions.DurableTask enthalten ist. Mit diesem Kontextobjekt können Sie andere Funktionen vom Typ Aktivität aufrufen und Eingabeparameter mit der zugehörigen CallActivityAsync-Methode übergeben.
Im Code wird E1_SayHello dreimal nacheinander mit unterschiedlichen Parameterwerten aufgerufen. Der Rückgabewert jedes Aufrufs wird der Liste outputs hinzugefügt, die am Ende der Funktion zurückgegeben wird.
function.json
Hier ist der Inhalt der Datei function.json für die Orchestratorfunktion angegeben, falls Sie Visual Studio Code oder das Azure-Portal für die Entwicklung verwenden. Die meisten function.json-Dateien für Orchestratoren ähneln dieser Datei stark.
Ein wichtiger Punkt ist der Bindungstyp orchestrationTrigger. Alle Orchestratorfunktionen müssen diesen Triggertyp verwenden.
Warnung
Um die Regel „keine E/A“ für Orchestratorfunktionen zu beachten, sollten Sie keine Eingabe- oder Ausgabebindungen verwenden, wenn Sie die Triggerbindung orchestrationTrigger einsetzen. Falls andere Eingabe- oder Ausgabebindungen erforderlich sind, sollten sie stattdessen im Kontext von activityTrigger-Funktionen verwendet werden, die vom Orchestrator aufgerufen werden. Weitere Informationen finden Sie im Artikel Codeeinschränkungen für Orchestratorfunktionen.
Alle JavaScript-Orchestrierungsfunktionen müssen das Modul durable-functions enthalten. Es handelt sich um eine Bibliothek, mit der Sie Durable Functions in JavaScript schreiben können. Zwischen einer Orchestratorfunktion und anderen JavaScript-Funktionen bestehen drei wesentliche Unterschiede:
Die Funktion wird in einem Aufruf der orchestrator-Methode des Moduls durable-functions umschlossen (hier df).
Die Funktion muss synchron sein. Da die „Orchestrator“-Methode den letzten Aufruf an „context.done“ verarbeitet, sollte die Funktion einfach „return“ lauten.
Das context-Objekt enthält ein dauerhaftes df-Orchestrierungskontextobjekt, mit dem Sie andere Aktivitätsfunktionen aufrufen und Eingabeparameter mit der zugehörigen callActivity-Methode übergeben können. Im Code wird E1_SayHello dreimal nacheinander mit unterschiedlichen Parameterwerten aufgerufen. Dabei wird yield verwendet, um anzugeben, dass für die Ausführung auf die Rückgabe der asynchronen Aufrufe der Aktivitätsfunktion gewartet werden muss. Der Rückgabewert jedes Aufrufs wird dem Array outputs hinzugefügt, das am Ende der Funktion zurückgegeben wird.
Alle JavaScript-Orchestrierungsfunktionen müssen das Modul durable-functions enthalten. Mit diesem Modul können Sie Durable Functions in JavaScript schreiben. Um das V4-Node-Programmiermodell verwenden zu können, müssen Sie die Vorschauversion v3.x von durable-functions installieren.
Zwischen einer Orchestratorfunktion und anderen JavaScript-Funktionen bestehen zwei wesentliche Unterschiede:
Die Funktion muss synchron sein. Die Funktion sollte einfach „zurückkehren“.
Das context-Objekt enthält ein dauerhaftes df-Orchestrierungskontextobjekt, mit dem Sie andere Aktivitätsfunktionen aufrufen und Eingabeparameter mit der zugehörigen callActivity-Methode übergeben können. Im Code wird sayHello dreimal nacheinander mit unterschiedlichen Parameterwerten aufgerufen. Dabei wird yield verwendet, um anzugeben, dass für die Ausführung auf die Rückgabe der asynchronen Aufrufe der Aktivitätsfunktion gewartet werden muss. Der Rückgabewert jedes Aufrufs wird dem Array outputs hinzugefügt, das am Ende der Funktion zurückgegeben wird.
Hinweis
Python Durable Functions sind nur für die Functions 3.0-Runtime verfügbar.
function.json
Hier ist der Inhalt der Datei function.json für die Orchestratorfunktion angegeben, falls Sie Visual Studio Code oder das Azure-Portal für die Entwicklung verwenden. Die meisten function.json-Dateien für Orchestratoren ähneln dieser Datei stark.
Ein wichtiger Punkt ist der Bindungstyp orchestrationTrigger. Alle Orchestratorfunktionen müssen diesen Triggertyp verwenden.
Warnung
Um die Regel „keine E/A“ für Orchestratorfunktionen zu beachten, sollten Sie keine Eingabe- oder Ausgabebindungen verwenden, wenn Sie die Triggerbindung orchestrationTrigger einsetzen. Falls andere Eingabe- oder Ausgabebindungen erforderlich sind, sollten sie stattdessen im Kontext von activityTrigger-Funktionen verwendet werden, die vom Orchestrator aufgerufen werden. Weitere Informationen finden Sie im Artikel Codeeinschränkungen für Orchestratorfunktionen.
Alle Python-Orchestrierungsfunktionen müssen das Paket durable-functions enthalten. Es handelt sich um eine Bibliothek, mit der Sie Durable Functions in Python schreiben können. Zwischen einer Orchestratorfunktion und anderen Python-Funktionen bestehen zwei wesentliche Unterschiede:
Die Datei muss die Orchestratorfunktion als Orchestrator registrieren, indem main = df.Orchestrator.create(<orchestrator function name>) am Ende der Datei angegeben wird. Dies hilft dabei, sie von anderen Funktionen (Hilfsfunktionen), zu unterscheiden, die in der Datei deklariert sind.
Mit diesem context-Objekt können Sie andere Funktionen vom Typ Aktivität aufrufen und Eingabeparameter mit der zugehörigen call_activity-Methode übergeben. Im Code wird E1_SayHello dreimal nacheinander mit unterschiedlichen Parameterwerten aufgerufen. Dabei wird yield verwendet, um anzugeben, dass für die Ausführung auf die Rückgabe der asynchronen Aufrufe der Aktivitätsfunktion gewartet werden muss. Der Rückgabewert jedes Aufrufs wird am Ende der Funktion zurückgegeben.
[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
Aktivitäten verwenden das ActivityTrigger-Attribut. Verwenden Sie den bereitgestellten IDurableActivityContext, um aktivitätsbezogene Aktionen auszuführen, z. B. den Zugriff auf den Eingabewert mit GetInput<T>.
Die Implementierung von E1_SayHello ist ein relativ einfacher Zeichenfolgen-Formatierungsvorgang.
Anstatt an einen IDurableActivityContext zu binden, können Sie direkt an den Typ binden, der an die Aktivitätsfunktion übergeben wird. Beispiel:
Die Datei function.json für die Aktivitätsfunktion E1_SayHello ähnelt der Datei von E1_HelloSequence, aber es wird nicht der Bindungstyp orchestrationTrigger, sondern activityTrigger verwendet.
Alle Aktivitätsfunktionen, die von einer Orchestrierungsfunktion aufgerufen werden, müssen die activityTrigger-Bindung verwenden.
Die Implementierung von E1_SayHello ist ein relativ einfacher Zeichenfolgen-Formatierungsvorgang.
E1_SayHello/index.js
module.exports = function (context) {
context.done(null, `Hello ${context.bindings.name}!`);
};
Im Gegensatz zu einer Orchestrierungsfunktion erfordert eine Aktivitätsfunktion keine spezielle Einrichtung. Die von der Orchestratorfunktion übergebene Eingabe befindet sich im Objekt context.bindings unter dem Namen der Bindung activityTrigger, in diesem Fall context.bindings.name. Der Name der Bindung kann als Parameter der exportierten Funktion eingerichtet werden und der Zugriff darauf direkt erfolgen. Dies ist bei dem Beispielcode der Fall.
Die Implementierung von sayHello ist ein relativ einfacher Zeichenfolgen-Formatierungsvorgang.
Im Gegensatz zu einer Orchestrierungsfunktion erfordert eine Aktivitätsfunktion keine spezielle Einrichtung. Die von der Orchestratorfunktion an sie übergebene Eingabe ist das erste Argument für die Funktion. Das zweite Argument ist der Aufrufkontext, der in diesem Beispiel nicht verwendet wird.
E1_SayHello/function.json
Die Datei function.json für die Aktivitätsfunktion E1_SayHello ähnelt der Datei von E1_HelloSequence, aber es wird nicht der Bindungstyp orchestrationTrigger, sondern activityTrigger verwendet.
Im Gegensatz zu einer Orchestratorfunktion erfordert eine Aktivitätsfunktion keine spezielle Einrichtung. Die von der Orchestratorfunktion an sie übergebene Eingabe ist direkt als Parameter für die Funktion verfügbar.
Clientfunktion „HttpStart“
Sie können eine Instanz der Orchestratorfunktion mithilfe einer Clientfunktion starten. Sie verwenden die per HTTP ausgelöste HttpStart-Funktion, um Instanzen von E1_HelloSequence zu starten.
public static class HttpStart
{
[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[DurableClient] IDurableClient 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);
}
}
Um mit Orchestratoren zu interagieren, muss die Funktion eine DurableClient-Eingabebindung enthalten. Mit dem Client starten Sie die Orchestrierung. Er kann Ihnen außerdem helfen, eine HTTP-Antwort zurückzugeben, die URLs zum Überprüfen des Status der neuen Orchestrierung enthält.
Verwenden Sie df.getClient, um ein DurableOrchestrationClient-Objekt zu erhalten. Mit dem Client starten Sie die Orchestrierung. Er kann Ihnen außerdem helfen, eine HTTP-Antwort zurückzugeben, die URLs zum Überprüfen des Status der neuen Orchestrierung enthält.
Um Orchestratoren zu verwalten und mit ihnen zu interagieren, benötigt die Funktion eine durableClient-Eingabebindung. Diese Bindung muss im extraInputs-Argument angegeben werden, wenn die Funktion registriert wird. Eine durableClient-Eingabe kann durch Aufrufen von df.input.durableClient() abgerufen werden.
Verwenden Sie df.getClient, um ein DurableClient-Objekt zu erhalten. Mit dem Client starten Sie die Orchestrierung. Er kann Ihnen außerdem helfen, eine HTTP-Antwort zurückzugeben, die URLs zum Überprüfen des Status der neuen Orchestrierung enthält.
Um mit Ochestratoren zu interagieren, muss die Funktion eine durableClientEingabebindung enthalten.
HttpStart/__init__.py
import logging
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new(req.route_params["functionName"], None, None)
logging.info(f"Started orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)
Verwenden Sie DurableOrchestrationClient, um einen Durable Functions-Client abzurufen. Mit dem Client starten Sie die Orchestrierung. Er kann Ihnen außerdem helfen, eine HTTP-Antwort zurückzugeben, die URLs zum Überprüfen des Status der neuen Orchestrierung enthält.
Ausführen des Beispiels
Senden Sie die folgende HTTP POST-Anforderung an die HttpStart-Funktion, um die E1_HelloSequence-Orchestrierung auszuführen.
POST http://{host}/orchestrators/E1_HelloSequence
Hinweis
Im vorherigen HTTP-Ausschnitt wird davon ausgegangen, dass ein Eintrag in der Datei host.json vorhanden ist, der das Standardpräfix api/ aus den URLs aller HTTP-Triggerfunktionen entfernt. Sie finden das Markup für diese Konfiguration in der Datei host.json in den Beispielen.
Wenn Sie das Beispiel z. B. in einer Funktions-App namens „myfunctionapp“ ausführen, ersetzen Sie „{host}“ durch „myfunctionapp.azurewebsites.net“.
Das Ergebnis ist eine HTTP 202-Antwort, die wie folgt aussehen kann (hier gekürzt):
An diesem Punkt wird die Orchestrierung in die Warteschlange eingereiht und sofort ausgeführt. Die URL im Header Location kann verwendet werden, um den Status der Ausführung zu überprüfen.
GET http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
Das Ergebnis ist der Status der Orchestrierung. Die Ausführung und der Abschluss werden schnell durchgeführt, sodass Sie den Status Completed (Abgeschlossen) mit dieser Antwort sehen (hier gekürzt):
Sie sehen, dass das runtimeStatus-Element der Instanz Completed lautet und dass output das per JSON serialisierte Ergebnis der Ausführung der Orchestratorfunktion enthält.
Hinweis
Sie können eine ähnliche Startlogik auch für andere Triggertypen wie queueTrigger, eventHubTrigger oder timerTrigger implementieren.
Sehen Sie sich die Protokolle zur Funktionsausführung an. Die Funktion E1_HelloSequence wurde mehrmals gestartet und abgeschlossen. Dies liegt am Wiedergabeverhalten, das im Thema Orchestrierungszuverlässigkeit beschrieben wird. Andererseits ist es nur zu drei Ausführungen von E1_SayHello gekommen, da diese Funktionsausführungen nicht wiedergegeben werden.
Nächste Schritte
In diesem Beispiel wird eine einfache Funktionsverkettungsorchestrierung veranschaulicht. Im nächsten Beispiel wird die Implementierung des Musters „Auffächern nach außen/innen“ gezeigt.