Compartilhar via


Diagnóstico no Durable Functions no Azure

Há várias opções para diagnosticar problemas com as Funções Duráveis. Algumas dessas opções são as mesmas usadas para funções regulares e algumas delas são exclusivas das Funções Duráveis.

Application Insights

O Application Insights é a maneira recomendada de fazer diagnóstico e monitoramento no Azure Functions. O mesmo se aplica às Funções Duráveis. Para obter uma visão geral de como usar o Application Insights em seu aplicativo de funções, consulte Monitor o Azure Functions.

A Extensão Durável do Azure Functions também emite eventos de acompanhamento, que permitem rastrear a execução de uma orquestração de ponta a ponta. Eles podem ser encontrados e consultados usando a ferramenta Application Insights Analytics no portal do Azure.

Acompanhamento de dados

Cada evento de ciclo de vida de uma instância de orquestração faz com que um evento de acompanhamento seja gravado na coleção de rastreamentos no Application Insights. Esse evento tem um conteúdo customDimensions com vários campos. Todos os nomes de campo são prefixados com prop__.

  • hubName: o nome do hub de tarefas no qual suas orquestrações estão em execução.
  • appName: o nome do aplicativo de funções. Esse campo é útil quando você tem vários aplicativos de funções compartilhando a mesma instância do Application Insights.
  • slotName: o slot de implantação no qual o aplicativo de funções atual está sendo executado. Esse campo é útil quando você aproveitar os slots de implantação para controlar a versão das suas orquestrações.
  • functionName: o nome da função de orquestrador ou atividade.
  • functionType: o tipo da função, como Orquestrador ou Atividade.
  • instanceId: a ID exclusiva da instância de orquestração.
  • state: o estado de execução do ciclo de vida da instância. Os valores válidos incluem:
    • Scheduled: a função foi agendada para execução, mas ainda não começou a ser executada.
    • Started: a função começou a ser executada, mas não ainda esperou ou foi concluída.
    • Awaited: o orquestrador agendou algum trabalho e está aguardando sua conclusão.
    • Listening: o orquestrador está escutando uma notificação de evento externo.
    • Completed: a função foi concluída com êxito.
    • Failed: a função falhou com um erro.
  • reason: dados adicionais associados ao evento de acompanhamento. Por exemplo, se uma instância estiver aguardando uma notificação de evento externo, esse campo indica o nome do evento que ela está aguardando. Se uma função tiver falhado, esse campo conterá detalhes do erro.
  • isReplay: valor booliano que indica se o evento de acompanhamento deve ter a execução reproduzida.
  • extensionVersion: a versão da extensão da Tarefa Durável. Esse dado da versão é especialmente importante ao relatar possíveis bugs na extensão. Instâncias de execução longa podem relatar várias versões se uma atualização ocorrer durante sua execução.
  • sequenceNumber: número de sequência de execução para um evento. Combinado com o carimbo de data/hora ajuda a ordenar os eventos por tempo de execução. Observe que esse número será redefinido para zero se o host for reiniciado enquanto a instância estiver em execução, portanto, primeiro é importante sempre classificar pelo carimbo de data/hora e, depois, sequenceNumber.

O detalhamento dos dados de acompanhamento emitidos para o Application Insights pode ser configurado na seção logger (Functions 1.x) ou logging (Functions 2.0.x) do arquivo host.json.

Functions 1.0

{
    "logger": {
        "categoryFilter": {
            "categoryLevels": {
                "Host.Triggers.DurableTask": "Information"
            }
        }
    }
}

Functions 2.0

{
    "logging": {
        "logLevel": {
            "Host.Triggers.DurableTask": "Information",
        },
    }
}

Por padrão, todos os eventos de acompanhamento de não reprodução são emitidos. O volume dos dados pode ser reduzido definindo Host.Triggers.DurableTask como "Warning" ou "Error". Nesse caso, os eventos de acompanhamento serão emitidos somente para situações excepcionais. Para habilitar a emissão dos eventos de reprodução de orquestração detalhados, defina o logReplayEvents como true no arquivo de configuração host.json.

Observação

Por padrão, a amostragem da telemetria do Application Insights é feita segundo o Azure Functions runtime, para evitar a emissão de dados com frequência excessiva. Isso pode fazer com que informações de acompanhamento sejam perdidas quando muitos eventos de ciclo de vida ocorrerem em um curto período. O artigo sobre Monitoramento no Azure Functions explica como configurar esse comportamento.

As entradas e saídas de orquestrador, atividade e funções de entidade não são registradas por padrão. Esse comportamento padrão é recomendado porque as entradas e saídas de registro em log podem aumentar os custos do Application Insights. Os conteúdos de entrada e de saída da função também podem conter informações confidenciais. Em vez disso, o número de bytes para entradas e saídas de função é registrado em log vez de conteúdos reais por padrão. Se você quiser que a extensão Durable Functions registre os conteúdos de entrada e saída completos, defina a propriedade traceInputsAndOutputs como true no arquivo de configuração host.json.

Consulta de instância única

A consulta a seguir mostra dados de acompanhamento históricos de uma única instância de orquestração da função Sequência Hello. Ela é gravada usando a Linguagem de Consulta do Kusto. Ela filtra a execução de reproduções para que somente o caminho de execução lógico seja mostrado. Os eventos podem ser ordenados classificando por timestamp e sequenceNumber, conforme mostrado na consulta abaixo:

let targetInstanceId = "ddd1aaa685034059b545eb004b15d4eb";
let start = datetime(2018-03-25T09:20:00);
traces
| where timestamp > start and timestamp < start + 30m
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = customDimensions["prop__functionName"]
| extend instanceId = customDimensions["prop__instanceId"]
| extend state = customDimensions["prop__state"]
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend sequenceNumber = tolong(customDimensions["prop__sequenceNumber"])
| where isReplay != true
| where instanceId == targetInstanceId
| sort by timestamp asc, sequenceNumber asc
| project timestamp, functionName, state, instanceId, sequenceNumber, appName = cloud_RoleName

O resultado é uma lista de eventos de rastreamento que mostra o caminho de execução da orquestração, incluindo quaisquer funções de atividade ordenadas pelo tempo de execução em ordem crescente.

Consulta ordenada de instância única do Application Insights

Consulta de resumo da instância

A consulta a seguir exibe o status de todas as instâncias de orquestração que foram executadas em um intervalo de tempo especificado.

let start = datetime(2017-09-30T04:30:00);
traces
| where timestamp > start and timestamp < start + 1h
| where customDimensions.Category == "Host.Triggers.DurableTask"
| extend functionName = tostring(customDimensions["prop__functionName"])
| extend instanceId = tostring(customDimensions["prop__instanceId"])
| extend state = tostring(customDimensions["prop__state"])
| extend isReplay = tobool(tolower(customDimensions["prop__isReplay"]))
| extend output = tostring(customDimensions["prop__output"])
| where isReplay != true
| summarize arg_max(timestamp, *) by instanceId
| project timestamp, instanceId, functionName, state, output, appName = cloud_RoleName
| order by timestamp asc

O resultado é uma lista de IDs de instância e seu status de runtime atual.

Consulta de instância única do Application Insights

Registro em log do Durable Task Framework

Os logs de extensão duráveis são úteis para entender o comportamento da lógica de orquestração. No entanto, esses logs nem sempre contêm informações suficientes para depurar problemas de desempenho e confiabilidade no nível da estrutura. A partir da versão v2.3.0 da extensão Durable, os logs emitidos pelo DTFx (Durable Task Framework) subjacente também estão disponíveis para coleta.

Ao ver os logs emitidos pelo DTFx, é importante entender que o mecanismo DTFx é composto por dois componentes: o mecanismo de expedição principal (DurableTask.Core) e um dos muitos provedores de armazenamento com suporte (Durable Functions usa DurableTask.AzureStorage por padrão, mas há outras opções disponíveis).

  • DurableTask.Core: execução de orquestração principal, telemetria e logs de agendamento de nível inferior.
  • DurableTask.AzureStorage: logs de back-end específicos para o provedor de estado do Armazenamento do Azure. Esses logs incluem interações detalhadas com as filas internas, os blobs e as tabelas de armazenamento usadas para armazenar e buscar o estado de orquestração interno.
  • DurableTask.Netherite: os logs de back-end específicos para o provedor de armazenamento Netherite, se habilitado.
  • DurableTask.SqlServer: os logs de back-end específicos para o provedor de armazenamento do MSSQL (Microsoft SQL), se habilitado.

Você pode habilitar esses logs atualizando a seção logging/logLevel do seu arquivo host.json no aplicativo de funções. O exemplo a seguir mostra como habilitar os logs de aviso e de erro de DurableTask.Core e DurableTask.AzureStorage:

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "DurableTask.AzureStorage": "Warning",
      "DurableTask.Core": "Warning"
    }
  }
}

Se você tiver o Application Insights habilitado, esses logs serão adicionados automaticamente à coleção trace. Você pode pesquisá-los da mesma maneira que pesquisa outros logs trace usando as consultas do Kusto.

Observação

Para aplicativos de produção, é recomendável habilitar DurableTask.Core e os logs do provedor de armazenamento apropriado (por exemplo, DurableTask.AzureStorage) usando o filtro "Warning". Filtros de detalhes mais altos, como "Information", são muito úteis para depurar problemas de desempenho. No entanto, esses eventos de log são de alto volume e podem aumentar significativamente os custos de armazenamento de dados do Application Insights.

A consulta do Kusto a seguir mostra como consultar logs do DTFx. A parte mais importante da consulta é where customerDimensions.Category startswith "DurableTask" que filtra os resultados para os logs nas categorias DurableTask.Core e DurableTask.AzureStorage.

traces
| where customDimensions.Category startswith "DurableTask"
| project
    timestamp,
    severityLevel,
    Category = customDimensions.Category,
    EventId = customDimensions.EventId,
    message,
    customDimensions
| order by timestamp asc 

O resultado é um conjunto de logs gravado pelos provedores de log do Durable Task Framework.

Resultados da consulta do DTFx do Application Insights

Para obter mais informações sobre quais eventos de log estão disponíveis, veja a Documentação de log estruturado do Durable Task Framework no GitHub.

Registro em log do aplicativo

É importante ter em mente o comportamento de reprodução do orquestrador ao gravar logs diretamente de uma função de orquestrador. Por exemplo, considere a seguinte função de orquestrador:

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

Os dados de log resultantes serão semelhantes ao seguinte exemplo de saída:

Calling F1.
Calling F1.
Calling F2.
Calling F1.
Calling F2.
Calling F3.
Calling F1.
Calling F2.
Calling F3.
Done!

Observação

Lembre-se de que, embora os logs declarem estar chamando F1, F2 e F3, essas funções realmente são chamadas apenas na primeira vez em que são encontradas. Chamadas posteriores que ocorrem durante a reprodução são ignoradas e as saídas são reproduzidas para a lógica do orquestrador.

Se quiser registrar no log apenas as execuções sem reproduções, você poderá gravar uma expressão condicional para registrar apenas se o sinalizador “for reproduzindo” for false. Considere o exemplo anterior, mas desta vez com verificações de reprodução.

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    if (!context.IsReplaying) log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    if (!context.IsReplaying) log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    if (!context.IsReplaying) log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

A partir do Durable Functions 2.0, as funções do .NET Orchestrator também têm a opção de criar um ILogger que filtra automaticamente as instruções de log durante a reprodução. Essa filtragem automática é feita usando a API IDurableOrchestrationContext.CreateReplaySafeLogger(ILogger).

[FunctionName("FunctionChain")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context,
    ILogger log)
{
    log = context.CreateReplaySafeLogger(log);
    log.LogInformation("Calling F1.");
    await context.CallActivityAsync("F1");
    log.LogInformation("Calling F2.");
    await context.CallActivityAsync("F2");
    log.LogInformation("Calling F3");
    await context.CallActivityAsync("F3");
    log.LogInformation("Done!");
}

Observação

O exemplo de C# anterior é para o 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.

Com as alterações mencionadas anteriormente, a saída do log é a seguinte:

Calling F1.
Calling F2.
Calling F3.
Done!

Status personalizados

O status de orquestração personalizado permite que você defina um valor de status personalizado para a função do orquestrador. Esse status personalizado é então visível para clientes externos por meio da API de consulta de status HTTP ou por meio de chamadas de API específicas de linguagem. O status de orquestração personalizado possibilita um monitoramento mais rico para funções do orquestrador. Por exemplo, o código de função do orquestrador pode incluir a API "definir status personalizado" para atualizar o progresso de uma operação demorada. Um cliente, como uma página da web ou outro sistema externo pode, em seguida, consultar periodicamente as APIs de consulta de status HTTP para informações de andamento mais ricas. O código de exemplo para definir um valor de status personalizado em uma função de orquestrador é fornecido abaixo:

[FunctionName("SetStatusTest")]
public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // ...do work...

    // update the status of the orchestration with some arbitrary data
    var customStatus = new { completionPercentage = 90.0, status = "Updating database records" };
    context.SetCustomStatus(customStatus);

    // ...do more work...
}

Observação

O exemplo C# anterior é para o Durable Functions 2.x. Para Durable Functions 1.x, você deve usar 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.

Durante a execução da orquestração, clientes externos podem buscar este status personalizado:

GET /runtime/webhooks/durabletask/instances/instance123?code=XYZ

O clientes terão a seguinte resposta:

{
  "runtimeStatus": "Running",
  "input": null,
  "customStatus": { "completionPercentage": 90.0, "status": "Updating database records" },
  "output": null,
  "createdTime": "2017-10-06T18:30:24Z",
  "lastUpdatedTime": "2017-10-06T19:40:30Z"
}

Aviso

O conteúdo do status personalizado é limitado a 16 KB de texto UTF-16 JSON porque ele precisa ser capaz de caber em uma coluna de Armazenamento de Tabelas do Azure. Você pode usar o armazenamento externo se precisar de conteúdo maior.

Rastreamento Distribuído

O Rastreamento Distribuído rastreia solicitações e mostra como diferentes serviços interagem entre si. No Durable Functions, ele também correlaciona orquestrações e atividades em conjunto. Isso é útil para entender quanto tempo as etapas da orquestração levam em relação a toda a orquestração. Também é útil entender onde um aplicativo está tendo um problema ou onde uma exceção foi gerada. Esse recurso tem suporte para todos os idiomas e provedores de armazenamento.

Observação

O Rastreamento Distribuído V2 requer Durable Functions v2.12.0 ou superior. Além disso, o Rastreamento Distribuído V2 está em um estado de visualização e, portanto, alguns padrões de funções duráveis não são instrumentados. Por exemplo, as operações de Entidades Duráveis não são instrumentadas e os rastreamentos não aparecerão no Application Insights.

Configurando o rastreamento distribuído

Para configurar o rastreamento distribuído, atualize o host.json e configure um recurso do Application Insights.

host. JSON

"durableTask": {
  "tracing": {
    "distributedTracingEnabled": true,
    "Version": "V2"
  }
}

Application Insights

Se o aplicativo de funções não estiver configurado com um recurso do Application Insights, configure-o seguindo as instruções aqui.

Inspecionando os rastreamentos

No recurso Application Insights, navegue até a Pesquisa de Transações. Nos resultados, verifique Request e Dependency os eventos que começam com prefixos específicos do Durable Functions (por exemplo orchestration:, activity:, etc.). Selecionar um desses eventos abrirá um gráfico de Gantt que mostrará o rastreamento distribuído de ponta a ponta.

Gráfico de Gantt mostrando o Rastreamento Distribuído do Application Insights.

Solução de problemas

Se você não vir os rastreamentos no Application Insights, aguarde cerca de cinco minutos após a execução do aplicativo para garantir que todos os dados sejam propagados para o recurso do Application Insights.

Depuração

O Azure Functions dá suporte à depuração do código de função diretamente e esse mesmo suporte se estende às Funções Duráveis, seja em execução no Azure ou localmente. No entanto, há alguns comportamentos a que você deve estar atento ao depurar:

  • Reprodução: funções do orquestrador são reproduzidas regularmente quando novas entradas são recebidas. Esse comportamento significa que uma única execução lógica de uma função do orquestrador pode atingir o mesmo ponto de interrupção várias vezes, especialmente se ele estiver definido no início do código da função.
  • Aguardar: sempre que um await é encontrado em uma função do orquestrador, ele leva o controle de volta para o dispatcher do Durable Task Framework. Se esta for a primeira vez que um determinado await foi encontrado, a tarefa associada nunca será retomada. Uma vez que a tarefa nunca seja retomada, percorrer a espera (F10 no Visual Studio) não é possível. Ignorar só funciona quando uma tarefa está sendo reproduzida.
  • Tempos limite de mensagem: o Durable Functions usam internamente mensagens de fila para acionar a execução de funções do orquestrador e de funções de atividade. Em um ambiente com várias VMs, interromper a depuração por longos períodos pode fazer com que outra VM receba a mensagem, resultando em uma execução duplicada. Esse comportamento também existe para funções de gatilho de fila regulares, mas é importante ressaltar neste contexto, uma vez que as filas são um detalhe de implementação.
  • Parando e iniciando: as mensagens no Durable Functions persistem entre as sessões de depuração. Se você parar a depuração e encerrar o processo de host local enquanto uma função durável estiver em execução, essa função poderá ser executada novamente de forma automática em uma sessão de depuração futura. Esse comportamento pode ser confuso quando inesperado. Usar um novo hub de tarefas ou limpar o conteúdo do hub de tarefas entre sessões de depuração é uma técnica para evitar esse comportamento.

Dica

Ao definir pontos de interrupção nas funções do orquestrador, se quiser interromper somente a execução que não é de repetição, você pode definir um ponto de interrupção condicional que interrompe somente se o valor "for reproduzindo" for false.

Armazenamento

Por padrão, as Funções Duráveis armazenam o estado no Armazenamento do Azure. Esse comportamento significa que você pode inspecionar o estado das suas orquestrações usando ferramentas como o Gerenciador de Armazenamento do Microsoft Azure.

Captura de tela do Gerenciador de Armazenamento do Microsoft Azure

Isso é útil para a depuração, pois você vê exatamente em qual estado uma orquestração pode estar. Mensagens nas filas também podem ser examinadas para saber qual trabalho está pendente (ou preso, em alguns casos).

Aviso

Embora seja conveniente ver o histórico de execução no armazenamento de tabelas, evite depender desta tabela. Ela pode mudar à medida que a extensão de Funções Duráveis evoluir.

Observação

Outros provedores de armazenamento podem ser configurados em vez do provedor de Armazenamento do Azure padrão. Dependendo do provedor de armazenamento configurado para o aplicativo, talvez seja necessário usar ferramentas diferentes para inspecionar o estado subjacente. Para obter mais informações, confira a documentação dos provedores de armazenamento do Durable Functions.

Monitoramento do Durable Functions

O Monitoramento do Durable Functions é uma ferramenta gráfica para monitorar, gerenciar e depurar instâncias de orquestração e entidades. O recurso está disponível como uma extensão do Visual Studio Code ou um aplicativo autônomo. Informações sobre configuração e uma lista de recursos podem ser encontradas nesse Wiki.

Guia de solução de problemas do Durable Functions

Para solucionar sintomas de problemas comuns, como orquestrações travadas, falha na inicialização, execução lenta etc., consulte este guia de solução de problemas.

Próximas etapas