Lidando com eventos externos nas Funções Duráveis (Azure Functions)

Funções de orquestrador têm a capacidade de aguardar e escutar eventos externos. Frequentemente, esse recurso das Funções Duráveis é útil para lidar com interação humana ou com outros gatilhos externos.

Observação

Eventos externos são operações assíncronas unidirecionais. Não são adequados para situações em que o cliente que envia o evento precisa de uma resposta síncrona da função de orquestrador.

Aguardar eventos

A API "wait-for-external-event" da associação de gatilho de orquestração permite que uma função de orquestrador aguarde e ouça de maneira assíncrona um evento entregue por um cliente externo. A função do orquestrador que está escutando declara o nome do evento e a forma dos dados que espera receber.

[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
    }
}

Observação

O código C# anterior é para Durable Functions 2.x. No Durable Functions 1.x, use DurableOrchestrationContext em vez de IDurableOrchestrationContext. Para obter mais informações sobre as diferenças entre versões, confira o artigo Versões do Durable Functions.

O exemplo anterior escuta um único evento específico e entra em ação quando ele é recebido.

Você pode escutar vários eventos ao mesmo tempo, como no exemplo a seguir, que aguarda uma de três notificações de evento possíveis.

[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)
    {
        // ...
    }
}

Observação

O código C# anterior é para Durable Functions 2.x. No Durable Functions 1.x, use DurableOrchestrationContext em vez de IDurableOrchestrationContext. Para obter mais informações sobre as diferenças entre versões, confira o artigo Versões do Durable Functions.

O exemplo anterior escuta qualquer um de vários eventos. Também é possível aguardar todos os eventos.

[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);
}

Observação

O código anterior é para Durable Functions 2.x. No Durable Functions 1.x, use DurableOrchestrationContext em vez de IDurableOrchestrationContext. Para obter mais informações sobre as diferenças entre versões, confira o artigo Versões do Durable Functions.

No .NET, se a carga do evento não puder ser convertida no T do tipo esperado, uma exceção será lançada.

A API "wait-for-external-event" aguarda indefinidamente alguma entrada. O aplicativo de funções pode ser descarregado com segurança enquanto aguarda. Se um evento chegar para esta instância de orquestração, ela será ativada automaticamente e processará imediatamente o evento.

Observação

Se o seu aplicativo de funções utiliza o Plano de Consumo, não são feitas cobranças enquanto uma função de orquestrador está aguardando uma tarefa de evento externo, independentemente do tempo de espera.

Tal como acontece com as funções de atividade, os eventos externos têm uma garantia de entrega pelo menos uma vez. Isso significa que, em determinadas condições (como reinicializações, dimensionamento, falhas etc.), seu aplicativo pode receber duplicatas do mesmo evento externo. Portanto, recomendamos que os eventos externos contenham algum tipo de ID que permita que eles sejam desduplicados manualmente em orquestradores.

Enviar eventos

Você pode usar a API "raise-event" definida pela associação de cliente de orquestração para enviar um evento externo para uma orquestração. Você também pode usar a API HTTP de geração de evento interna para enviar um evento externo para uma orquestração.

Um evento gerado inclui uma ID de instância, um eventName e um eventData como parâmetros. As funções do orquestrador manipulam esses eventos usando as APIs "wait-for-external-event". O eventName deve coincidir nas extremidades de envio e de recebimento para que o evento seja processado. Os dados do evento devem também ser serializáveis em JSON.

Internamente, os mecanismos de "raise-event" enfileiram uma mensagem que é captada pela função do orquestrador em espera. Se a instância não está aguardando o nome do evento especificado, a mensagem de evento é adicionada a uma fila na memória. Se posteriormente a instância de orquestração começa a escutar esse nome do evento, ela verifica a fila de mensagens de evento.

Observação

Se não houver nenhuma instância de orquestração com a ID da instância especificada, a mensagem de evento é descartada.

Abaixo, temos um exemplo de função disparada em fila que envia um evento de "Aprovação" para uma instância de função de orquestrador. A ID da instância de orquestração vem do corpo da mensagem da fila.

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

Observação

O código C# anterior é para Durable Functions 2.x. Para o Durable Functions 1.x, você deve usar o atributo OrchestrationClient em vez do atributo DurableClient, e deve usar o tipo de parâmetro DurableOrchestrationClient em vez de IDurableOrchestrationClient. Para obter mais informações sobre as diferenças entre versões, confira o artigo Versões do Durable Functions.

Internamente, a API "raise-event" enfileira uma mensagem que é captada pela função do orquestrador em espera. Se a instância não está aguardando o nome do evento especificado, a mensagem de evento é adicionada a um buffer na memória. Se mais tarde a instância de orquestração começar a escutar o nome do evento, ele verificará o buffer em busca de mensagens de evento e disparará a tarefa que estava esperando por isso.

Observação

Se não houver nenhuma instância de orquestração com a ID da instância especificada, a mensagem de evento é descartada.

HTTP

Veja a seguir um exemplo de uma solicitação HTTP que gera um evento de “Aprovação” para uma instância de orquestração.

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

"true"

Nesse caso, a ID da instância é codificada como MyInstanceId.

Próximas etapas