Recursos HTTP

O Durable Functions tem vários recursos que facilitam a incorporação de orquestrações e entidades duráveis em fluxos de trabalho HTTP. Este artigo entra em detalhes sobre alguns desses recursos.

Expondo APIs HTTP

Orquestrações e entidades podem ser invocadas e gerenciadas usando solicitações HTTP. A extensão Durable Functions expõe APIs HTTP internas. Ele também fornece APIs para interagir com orquestrações e entidades de dentro de funções acionadas por HTTP.

APIs HTTP incorporadas

A extensão Durable Functions adiciona automaticamente um conjunto de APIs HTTP ao host do Azure Functions. Com essas APIs, você pode interagir e gerenciar orquestrações e entidades sem escrever nenhum código.

As seguintes APIs HTTP internas são suportadas.

Consulte o artigo APIs HTTP para obter uma descrição completa de todas as APIs HTTP internas expostas pela extensão Durable Functions.

Descoberta de URL de API HTTP

A ligação do cliente de orquestração expõe APIs que podem gerar cargas úteis de resposta HTTP. Por exemplo, ele pode criar uma resposta contendo links para APIs de gerenciamento para uma instância de orquestração específica. Os exemplos a seguir mostram uma função de gatilho HTTP que demonstra como usar essa API para uma nova instância de orquestração:

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;

namespace VSSample
{
    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);
        }
    }
}

Iniciar uma função de orquestrador usando as funções de gatilho HTTP mostradas anteriormente pode ser feito usando qualquer cliente HTTP. O seguinte comando cURL inicia uma função orchestrator chamada DoWork:

curl -X POST https://localhost:7071/orchestrators/DoWork -H "Content-Length: 0" -i

Segue-se um exemplo de resposta para uma orquestração que tem abc123 como ID o seu ID. Alguns detalhes foram removidos para maior clareza.

HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Location: http://localhost:7071/runtime/webhooks/durabletask/instances/abc123?code=XXX
Retry-After: 10

{
    "id": "abc123",
    "purgeHistoryDeleteUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/abc123?code=XXX",
    "sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/abc123/raiseEvent/{eventName}?code=XXX",
    "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/abc123?code=XXX",
    "terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/abc123/terminate?reason={text}&code=XXX"
}

No exemplo anterior, cada um dos campos que terminam em Uri corresponde a uma API HTTP interna. Você pode usar essas APIs para gerenciar a instância de orquestração de destino.

Nota

O formato das URLs do webhook depende de qual versão do host do Azure Functions você está executando. O exemplo anterior é para o host do Azure Functions 2.0.

Para obter uma descrição de todas as APIs HTTP internas, consulte a referência da API HTTP.

Rastreamento de operação assíncrona

A resposta HTTP mencionada anteriormente foi projetada para ajudar a implementar APIs assíncronas HTTP de longa execução com funções duráveis. Este padrão é por vezes referido como o padrão do consumidor de sondagem. O fluxo cliente/servidor funciona da seguinte forma:

  1. O cliente emite uma solicitação HTTP para iniciar um processo de longa execução como uma função de orquestrador.
  2. O gatilho HTTP de destino retorna uma resposta HTTP 202 com um cabeçalho Location que tem o valor "statusQueryGetUri".
  3. O cliente sonda a URL no cabeçalho Location. O cliente continua a ver respostas HTTP 202 com um cabeçalho Location.
  4. Quando a instância termina ou falha, o ponto de extremidade no cabeçalho Location retorna HTTP 200.

Este protocolo permite a coordenação de processos de longa execução com clientes ou serviços externos que podem sondar um ponto de extremidade HTTP e seguir o cabeçalho Location. As implementações de cliente e servidor desse padrão são incorporadas às APIs HTTP de Funções Duráveis.

Nota

Por padrão, todas as ações baseadas em HTTP fornecidas pelos Aplicativos Lógicos do Azure dão suporte ao padrão de operação assíncrona padrão. Esse recurso torna possível incorporar uma função durável de longa duração como parte de um fluxo de trabalho de aplicativos lógicos. Você pode encontrar mais detalhes sobre o suporte de Aplicativos Lógicos para padrões HTTP assíncronos na documentação de ações e gatilhos de fluxo de trabalho dos Aplicativos Lógicos do Azure.

Nota

As interações com orquestrações podem ser feitas a partir de qualquer tipo de função, não apenas de funções acionadas por HTTP.

Para obter mais informações sobre como gerenciar orquestrações e entidades usando APIs de cliente, consulte o artigo Gerenciamento de instâncias.

Consumindo APIs HTTP

Conforme descrito nas restrições de código de função do orquestrador, as funções do orquestrador não podem fazer E/S diretamente. Em vez disso, eles normalmente chamam funções de atividade que fazem operações de E/S.

A partir do Durable Functions 2.0, as orquestrações podem consumir nativamente APIs HTTP usando a ligação de gatilho de orquestração.

O código de exemplo a seguir mostra uma função orchestrator fazendo uma solicitação HTTP de saída:

[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Makes an HTTP GET request to the specified endpoint
    DurableHttpResponse response = 
        await context.CallHttpAsync(HttpMethod.Get, url);

    if (response.StatusCode >= 400)
    {
        // handling of error codes goes here
    }
}

Usando a ação "chamar HTTP", você pode fazer as seguintes ações em suas funções de orquestrador:

  • Chame APIs HTTP diretamente de funções de orquestração, com algumas limitações que serão mencionadas posteriormente.
  • Suporta automaticamente padrões de sondagem de status HTTP 202 do lado do cliente.
  • Use as Identidades Gerenciadas do Azure para fazer chamadas HTTP autorizadas para outros pontos de extremidade do Azure.

A capacidade de consumir APIs HTTP diretamente das funções do orquestrador destina-se a ser uma conveniência para um determinado conjunto de cenários comuns. Você mesmo pode implementar todos esses recursos usando funções de atividade. Em muitos casos, as funções de atividade podem dar-lhe mais flexibilidade.

Tratamento HTTP 202

A API "call HTTP" pode implementar automaticamente o lado do cliente do padrão de consumidor de sondagem. Se uma API chamada retornar uma resposta HTTP 202 com um cabeçalho Location, a função orchestrator sondará automaticamente o recurso Location até receber uma resposta diferente de 202. Essa resposta será a resposta retornada ao código de função do orquestrador.

Nota

  1. As funções do Orchestrator também suportam nativamente o padrão de consumidor de sondagem do lado do servidor, conforme descrito em Rastreamento de operação assíncrona. Esse suporte significa que orquestrações em um aplicativo de função podem facilmente coordenar as funções do orquestrador em outros aplicativos de função. Isso é semelhante ao conceito de suborquestração , mas com suporte para comunicação entre aplicativos. Esse suporte é particularmente útil para o desenvolvimento de aplicativos no estilo microsserviço.
  2. Devido a uma limitação temporária, o padrão de sondagem HTTP interno não está disponível atualmente em JavaScript/TypeScript e Python.

Identidades geridas

O Durable Functions suporta nativamente chamadas para APIs que aceitam tokens do Microsoft Entra para autorização. Esse suporte usa identidades gerenciadas do Azure para adquirir esses tokens .

O código a seguir é um exemplo de uma função orquestradora. A função faz chamadas autenticadas para reiniciar uma máquina virtual usando a API REST de máquinas virtuais do Azure Resource Manager.

[FunctionName("RestartVm")]
public static async Task RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string subscriptionId = "mySubId";
    string resourceGroup = "myRG";
    string vmName = "myVM";
    string apiVersion = "2019-03-01";
    
    // Automatically fetches an Azure AD token for resource = https://management.core.windows.net/.default
    // and attaches it to the outgoing Azure Resource Manager API call.
    var restartRequest = new DurableHttpRequest(
        HttpMethod.Post, 
        new Uri($"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Compute/virtualMachines/{vmName}/restart?api-version={apiVersion}"),
        tokenSource: new ManagedIdentityTokenSource("https://management.core.windows.net/.default"));
    DurableHttpResponse restartResponse = await context.CallHttpAsync(restartRequest);
    if (restartResponse.StatusCode != HttpStatusCode.OK)
    {
        throw new ArgumentException($"Failed to restart VM: {restartResponse.StatusCode}: {restartResponse.Content}");
    }
}

No exemplo anterior, o parâmetro é configurado para adquirir tokens do Microsoft Entra para o tokenSource Azure Resource Manager. Os tokens são identificados pelo URI https://management.core.windows.net/.defaultdo recurso . O exemplo pressupõe que o aplicativo de função atual esteja sendo executado localmente ou tenha sido implantado como um aplicativo de função com uma identidade gerenciada. Presume-se que a identidade local ou a identidade gerenciada tenha permissão para gerenciar VMs no grupo myRGde recursos especificado.

No tempo de execução, a fonte de token configurada retorna automaticamente um token de acesso OAuth 2.0. Em seguida, a fonte adiciona o token como um token de portador ao cabeçalho Authorization da solicitação de saída. Este modelo é uma melhoria em relação à adição manual de cabeçalhos de autorização a solicitações HTTP pelos seguintes motivos:

  • A atualização do token é tratada automaticamente. Você não precisa se preocupar com tokens expirados.
  • Os tokens nunca são armazenados no estado de orquestração durável.
  • Você não precisa escrever nenhum código para gerenciar a aquisição de tokens.

Você pode encontrar um exemplo mais completo no exemplo de C# RestartVMs pré-compilado.

As identidades gerenciadas não estão limitadas ao gerenciamento de recursos do Azure. Você pode usar identidades gerenciadas para acessar qualquer API que aceite tokens de portador do Microsoft Entra, incluindo serviços do Azure da Microsoft e aplicativos Web de parceiros. A aplicação Web de um parceiro pode até ser outra aplicação funcional. Para obter uma lista dos serviços do Azure da Microsoft que dão suporte à autenticação com a ID do Microsoft Entra, consulte Serviços do Azure que oferecem suporte à autenticação do Microsoft Entra.

Limitações

O suporte interno para chamar APIs HTTP é um recurso de conveniência. Não é apropriado para todos os cenários.

As solicitações HTTP enviadas pelas funções do orquestrador e suas respostas são serializadas e persistidas como mensagens no provedor de armazenamento Durable Functions. Esse comportamento de enfileiramento persistente garante que as chamadas HTTP sejam confiáveis e seguras para repetição de orquestração. No entanto, o comportamento de fila persistente também tem limitações:

  • Cada solicitação HTTP envolve latência adicional quando comparada a um cliente HTTP nativo.
  • Dependendo do provedor de armazenamento configurado, mensagens grandes de solicitação ou resposta podem degradar significativamente o desempenho da orquestração. Por exemplo, ao usar o Armazenamento do Azure, as cargas úteis HTTP que são muito grandes para caber nas mensagens da Fila do Azure são compactadas e armazenadas no armazenamento de Blob do Azure.
  • Não há suporte para cargas úteis de streaming, fragmentadas e binárias.
  • A capacidade de personalizar o comportamento do cliente HTTP é limitada.

Se alguma dessas limitações puder afetar seu caso de uso, considere usar funções de atividade e bibliotecas de cliente HTTP específicas do idioma para fazer chamadas HTTP de saída.

Nota

Se você é um desenvolvedor .NET, você pode se perguntar por que esse recurso usa os tipos DurableHttpRequest e DurableHttpResponse em vez dos tipos internos .NET HttpRequestMessage e HttpResponseMessage.

Esta escolha de design é intencional. O principal motivo é que os tipos personalizados ajudam a garantir que os usuários não façam suposições incorretas sobre os comportamentos suportados do cliente HTTP interno. Tipos específicos para funções duráveis também tornam possível simplificar o design da API. Eles também podem disponibilizar mais facilmente recursos especiais, como integração de identidade gerenciada e o padrão de consumidor de sondagem.

Extensibilidade (somente .NET)

É possível personalizar o comportamento do cliente HTTP interno da orquestração usando a injeção de dependência .NET do Azure Functions. Esta capacidade pode ser útil para fazer pequenas mudanças comportamentais. Também pode ser útil para testar o cliente HTTP injetando objetos fictícios.

O exemplo a seguir demonstra o uso da injeção de dependência para desabilitar a validação de certificado TLS/SSL para funções de orquestrador que chamam pontos de extremidade HTTP externos.

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        // Register own factory
        builder.Services.AddSingleton<
            IDurableHttpMessageHandlerFactory,
            MyDurableHttpMessageHandlerFactory>();
    }
}

public class MyDurableHttpMessageHandlerFactory : IDurableHttpMessageHandlerFactory
{
    public HttpMessageHandler CreateHttpMessageHandler()
    {
        // Disable TLS/SSL certificate validation (not recommended in production!)
        return new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback =
                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
        };
    }
}

Próximos passos