Behandeln von externen Ereignissen in Durable Functions (Azure Functions)

Orchestratorfunktionen können warten und auf externe Ereignisse lauschen. Das Feature Durable Functions ist oft hilfreich für die Behandlung menschlicher Interaktion oder anderer externer Trigger.

Hinweis

Externe Ereignisse sind unidirektionale, asynchrone Vorgänge. Sie sind nicht geeignet für Situationen, in denen der Client, der das Ereignis sendet, eine synchrone Antwort von der Orchestratorfunktion benötigt.

Warten auf Ereignisse

Die wait-for-external-event-API der Orchestrierungstriggerbindung ermöglicht es einer Orchestratorfunktion, asynchron zu warten und auf ein Ereignis zu lauschen, das von einem externen Client geliefert wird. Die lauschende Orchestratorfunktion deklariert den Namen des Ereignisses und die Form der Daten, die sie zu empfangen erwartet.

[FunctionName("BudgetApproval")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool approved = await context.WaitForExternalEvent<bool>("Approval");
    if (approved)
    {
        // approval granted - do the approved action
    }
    else
    {
        // approval denied - send a notification
    }
}

Hinweis

Der vorherige C#-Code ist für Durable Functions 2.x vorgesehen. 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.

Im vorangehenden Beispiel wird auf ein bestimmtes einzelnes Ereignis gelauscht und bei Empfang eine entsprechende Aktion ausgeführt.

Sie können wie im folgenden Beispiel, in dem auf eine von drei möglichen Ereignisbenachrichtigungen gewartet wird, auf mehrere Ereignisse gleichzeitig lauschen.

[FunctionName("Select")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var event1 = context.WaitForExternalEvent<float>("Event1");
    var event2 = context.WaitForExternalEvent<bool>("Event2");
    var event3 = context.WaitForExternalEvent<int>("Event3");

    var winner = await Task.WhenAny(event1, event2, event3);
    if (winner == event1)
    {
        // ...
    }
    else if (winner == event2)
    {
        // ...
    }
    else if (winner == event3)
    {
        // ...
    }
}

Hinweis

Der vorherige C#-Code ist für Durable Functions 2.x vorgesehen. 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.

Im vorherigen Beispiel wird auf alle von mehreren Ereignissen gelauscht. Es ist auch möglich, auf alle Ereignisse zu warten.

[FunctionName("NewBuildingPermit")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string applicationId = context.GetInput<string>();

    var gate1 = context.WaitForExternalEvent("CityPlanningApproval");
    var gate2 = context.WaitForExternalEvent("FireDeptApproval");
    var gate3 = context.WaitForExternalEvent("BuildingDeptApproval");

    // all three departments must grant approval before a permit can be issued
    await Task.WhenAll(gate1, gate2, gate3);

    await context.CallActivityAsync("IssueBuildingPermit", applicationId);
}

Hinweis

Der vorherige Code ist für Durable Functions 2.x vorgesehen. 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.

Wenn in .NET die Ereignisnutzlast nicht in den erwarteten Typ T konvertiert werden kann, wird eine Ausnahme ausgelöst.

Die wait-for-external-event-API wartet unbegrenzt auf eine Eingabe. Die Funktionen-App kann während des Wartens problemlos entladen werden. Wenn ein Ereignis für diese Orchestrierungsinstanz eingeht, wird sie automatisch aktiviert und verarbeitet das Ereignis sofort.

Hinweis

Wenn Ihre Funktions-App den Verbrauchstarif verwendet, fallen keine Kosten an, während eine Orchestratorfunktion auf einen externen Ereignistask wartet, unabhängig davon, wie lange sie wartet.

Wie bei Aktivitätsfunktionen weisen externe Ereignisse eine Garantie von mindestens einer Zustellung auf. Ihre Anwendung kann somit unter bestimmten Bedingungen (Neustarts, Skalierung, Abstürze usw.), Duplikate desselben externen Ereignisses empfangen. Daher wird empfohlen, dass externe Ereignisse irgendeine ID enthalten, über die sie in Orchestratoren manuell dedupliziert werden können.

Senden von Ereignisse

Sie können die raise-event-API, die durch die Bindung des Orchestrierungsclients definiert ist, verwenden, um ein externes Ereignis an eine Orchestrierung zu senden. Sie können auch die integrierte HTTP-API zum Auslösen eines Ereignisses verwenden, um ein externes Ereignis an eine Orchestrierung zu senden.

Ein ausgelöstes Ereignis enthält eine Instanz-ID, einen Ereignisnamen (eventName) und Ereignisdaten (eventData) als Parameter. Orchestratorfunktionen verarbeiten diese Ereignisse über die wait-for-external-event-APIs. Der Ereignisname (eventName) muss sowohl auf der Sende- als auch auf der Empfangsseite übereinstimmen, damit das Ereignis verarbeitet wird. Die Ereignisdaten müssen außerdem JSON-serialisierbar sein.

Intern reihen die raise event-Mechanismen eine Nachricht in die Warteschlange ein, die von der wartenden Orchestratorfunktion aufgegriffen wird. Falls die Instanz nicht auf den angegebenen Ereignisnamen wartet, wird die Ereignisnachricht einer In-Memory-Warteschlange hinzugefügt. Wenn die Orchestrierungsinstanz später auf den Ereignisnamen lauscht, überprüft sie die Warteschlange auf Ereignisnachrichten.

Hinweis

Ist keine Orchestrierungsinstanz mit der angegebenen Instanz-ID vorhanden, wird die Ereignisnachricht verworfen.

Im Folgenden finden Sie eine durch eine Warteschlange ausgelöste Beispielfunktion, die ein „Genehmigungs“-Ereignis an eine Orchestratorfunktionsinstanz sendet. Die Orchestrierungsinstanz-ID stammt aus dem Text der Warteschlangennachricht.

[FunctionName("ApprovalQueueProcessor")]
public static async Task Run(
    [QueueTrigger("approval-queue")] string instanceId,
    [DurableClient] IDurableOrchestrationClient client)
{
    await client.RaiseEventAsync(instanceId, "Approval", true);
}

Hinweis

Der vorherige C#-Code ist für Durable Functions 2.x vorgesehen. Für Durable Functions 1.x müssen Sie das OrchestrationClient-Attribut anstelle des DurableClient-Attributs verwenden, und Sie müssen den DurableOrchestrationClient-Parametertyp anstelle von IDurableOrchestrationClient verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions-Versionen.

Intern reiht die raise event-API eine Nachricht in die Warteschlange ein, die von der wartenden Orchestratorfunktion aufgegriffen wird. Falls die Instanz nicht auf den angegebenen Ereignisnamen wartet, wird die Ereignisnachricht einem In-Memory-Puffer hinzugefügt. Wenn die Orchestrierungsinstanz später mit dem Lauschen auf diesen Ereignisnamen beginnt, wird der Puffer auf Ereignisnachrichten überprüft und der Task ausgelöst, der darauf wartete.

Hinweis

Ist keine Orchestrierungsinstanz mit der angegebenen Instanz-ID vorhanden, wird die Ereignisnachricht verworfen.

HTTP

Im Anschluss finden Sie ein Beispiel für eine HTTP-Anforderung, durch die ein Genehmigungsereignis für eine Orchestrierungsinstanz ausgelöst wird.

POST /runtime/webhooks/durabletask/instances/MyInstanceId/raiseEvent/Approval&code=XXX
Content-Type: application/json

"true"

In diesem Fall ist die Instanz-ID als MyInstanceId hartcodiert.

Nächste Schritte

Human interaction in Durable Functions - Phone verification sample (Menschliche Interaktion in Durable Functions – Telefonüberprüfungsbeispiel)