Resolução de problemas comuns do SDK de Tarefas Duráveis

Este artigo ajuda-o a diagnosticar e corrigir problemas comuns ao construir aplicações com os Durable Task SDKs portáteis. Encontre o seu cenário na lista seguinte e siga os passos ligados para diagnosticar e resolver o problema.

Cenários comuns

Ligação e configuração

Orquestrações

Atividades

gRPC

Registo e diagnóstico

Linguagem específica

Estes SDKs ligam-se ao backend Durable Task Scheduler e correm em qualquer plataforma de alojamento, incluindo Azure Container Apps, Kubernetes e VMs.

Observação

Este guia cobre os SDKs portáteis de Tarefas Duráveis. Para questões específicas do serviço Planificador de Tarefas Duradouras, consulte Solucionar Problemas do Agendador de Tarefas Durável. Para questões específicas da extensão Durable Functions, consulte Durable Functions guia de resolução de problemas.

Sugestão

O painel de monitorização do Durable Task Scheduler é útil para inspecionar o estado da orquestração, visualizar o histórico de execução e identificar falhas. Use-o juntamente com este guia para acelerar a resolução de problemas.

Encontra o teu problema

Mensagem de erro ou sintoma Seção
connection refused ou failed to connect no arranque O emulador não está a correr ou é inacessível
Erros de análise de cadeias de ligação ou erros de autenticação no arranque O formato da string de ligação está incorreto
Trabalhador conecta-se, mas as orquestrações não começam O Task Hub não existe
401 Unauthorized ou erros de identidade/função no Azure Falhas de autenticação baseada em identidade em Azure
Orquestração bloqueada em "Pendente" Orquestração está presa no estado "Pendente"
Orquestração presa em "Running" A orquestração está presa no estado "Em execução"
Falhas de repetição, ciclos infinitos ou comportamentos inesperados Código orquestrador não determinístico
Erros de incompatibilidade de tipos ou de serialização JSON Erros de serialização e desserialização
activity not found Atividade não encontrada
RESOURCE_EXHAUSTED ou message too large Limite de tamanho de mensagem gRPC ultrapassado
CANCELLED: Cancelled on client Durante o encerramento Erros de cancelamento do fluxo durante o desligamento
CS0419 / VSTHRD105 avisos quebram compilação Avisos de geradores de código interrompem compilações (C#)
OrchestratorBlockedException (Java) OrchestratorBlockedException (Java)
Erro pouco útil ao usar retry_policy (Python) A Política de Tentativa exige max_retry_interval (Python)

Problemas de ligação e configuração

O emulador não está a correr ou é inacessível

Se a sua aplicação falhar no arranque com um erro de ligação como "ligação recusada" ou "falhou a ligar", verifique se o emulador Durable Task Scheduler está a correr e acessível.

  1. Verifique se o contentor Docker do emulador está a funcionar:

    docker ps | grep durabletask
    
  2. Verifica se os mapeamentos das portas estão corretos. O emulador expõe duas portas:

    • 8080—endpoint gRPC (utilizado pela sua aplicação)
    • 8082—UI de Dashboard

    Se estiveres a usar um mapeamento de portas personalizado, atualiza a tua cadeia de ligação para corresponder à porta host mapeada para a porta container 8080.

  3. Testar a conectividade com o endpoint gRPC:

    curl -v http://localhost:8080
    

    Uma recusa de ligação indica que o contentor não está a correr ou que o mapeamento de portas está incorreto.

O formato da string de ligação está incorreto

Erros na cadeia de ligação são uma causa comum de falhas no arranque. Verifica se a tua cadeia de ligação corresponde ao formato esperado.

Desenvolvimento local (emulador):

Endpoint=http://localhost:8080;Authentication=None

Azure (identidade gerida):

Endpoint=https://<scheduler-name>.durabletask.io;Authentication=ManagedIdentity

Azure (identidade gerida atribuída pelo utilizador):

Endpoint=https://<scheduler-name>.durabletask.io;Authentication=ManagedIdentity;ClientID=<client-id>

Erros comuns:

  • Usando https para o emulador local (o emulador usa http)
  • Usar http para Azure endpoints (Azure requer https)
  • Omitir o parâmetro Authentication
  • Usar a porta do painel (8082) em vez da porta gRPC (8080)

Cliente ou trabalhador falha em ligar-se

Verifique se o seu cliente e trabalhador estão configurados com a cadeia de ligação correta e o nome do hub de tarefas.

using Microsoft.DurableTask.Client.AzureManaged;
using Microsoft.DurableTask.Worker.AzureManaged;

var connectionString = "Endpoint=http://localhost:8080;Authentication=None";

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddDurableTaskWorker()
    .AddTasks(registry =>
    {
        registry.AddOrchestrator<MyOrchestrator>();
        registry.AddActivity<MyActivity>();
    })
    .UseDurableTaskScheduler(connectionString);

builder.Services.AddDurableTaskClient()
    .UseDurableTaskScheduler(connectionString);

O Task Hub não existe

Se as suas orquestrações falharem ao arrancar ou o trabalhador se conectar mas não processar o trabalho, o hub de tarefas pode não existir no agendador. O emulador normalmente cria centros de tarefas automaticamente usando a DTS_TASK_HUB_NAMES variável de ambiente.

Verifica se o emulador foi iniciado com o nome correto do hub de tarefas:

docker run -d -p 8080:8080 -p 8082:8082 \
  -e DTS_TASK_HUB_NAMES="my-taskhub" \
  mcr.microsoft.com/dts/dts-emulator:latest

Para agendadores alojados no Azure, crie o hub de tarefas usando o CLI do Azure:

az durabletask taskhub create \
  --resource-group <resource-group> \
  --scheduler-name <scheduler-name> \
  --name <taskhub-name>

Falhas de autenticação baseada em identidade no Azure

Se a sua aplicação corre localmente mas falha quando implementada no Azure, o problema provavelmente está relacionado com a autenticação:

  1. Verifique se a identidade gerida está atribuída à sua aplicação (atribuída pelo sistema ou pelo utilizador).
  2. Verifique se a identidade possui o papel de Contribuidor de Dados de Tarefas Duradouras no recurso do agendador ou no hub de tarefas específico.
  3. Certifique-se de que o cadeia de ligação usa o valor correto Authentication (ManagedIdentity). Em Python, passa uma instância DefaultAzureCredential() como parâmetro token_credential em vez de usar um cadeia de ligação.
  4. Para identidades atribuídas pelo utilizador, verifique se o ClientID na cadeia de conexão corresponde ao ID do cliente da identidade.

Para instruções detalhadas, consulte Configurar identidade gerida para o Durable Task Scheduler.

Problemas de orquestração

A orquestração está presa no estado "Pendente"

Uma orquestração em estado "Pendente" indica que estava agendada, mas um trabalhador ainda não a iniciou. Confira os seguintes itens:

  • O trabalhador está a correr. Garante que o teu processo de trabalho está a correr e ligado ao mesmo hub de tarefas onde a orquestração foi agendada.
  • O nome do Task Hub coincide. Verifica se tanto o trabalhador como o cliente fazem referência ao mesmo nome do hub de tarefas. Uma incompatibilidade faz com que o trabalhador consulte um hub de tarefa diferente.
  • O Orchestrator está registado. A função ou classe do orquestrador referida no agendamento deve ser registada junto do trabalhador.

Verifique se a classe de orquestrador está registada no serviço de trabalho durante o arranque. Se usar geradores de fonte ([DurableTask] atributo), o registo é automático. Caso contrário, registe manualmente:

builder.Services.AddDurableTaskWorker()
    .AddTasks(registry =>
    {
        registry.AddOrchestrator<MyOrchestrator>();
        registry.AddActivity<MyActivity>();
    })
    .UseDurableTaskScheduler(connectionString);

A orquestração está presa no estado "em execução"

Uma orquestração presa em "Em Execução" normalmente significa que está à espera de uma tarefa que ainda não foi concluída. Para diagnosticar, abra o painel do Durable Task Scheduler e inspecione o histórico de execução da orquestração. Verifique o último evento concluído — o próximo evento da sequência é aquele que está a impedir o avanço.

Causas comuns:

  • Atividade não registada. A orquestração chama um nome de atividade que não está registado com o trabalhador. O painel mostra um TaskScheduled evento sem TaskCompleted correspondente. Verifique se o nome da atividade corresponde ao código do seu orquestrador e ao registo do trabalhador (veja Atividade não encontrada).
  • Estou à espera de um evento externo. A orquestração chama waitForExternalEvent e o evento ainda não foi ativado. O painel mostra que um EventRaised evento é esperado, mas não se encontra presente. Verifique o nome do evento e se o remetente está a direcionar o ID correto da instância de orquestração.
  • Estou à espera de um temporizador durável. A orquestração cria um temporizador que ainda não expirou. O painel mostra um evento TimerCreated. Espera que o temporizador dispare, ou verifica se a duração do temporizador é maior do que o esperado.
  • Atividade lança uma exceção não tratada. O painel mostra um evento TaskFailed. Verifique os detalhes da falha relacionados à mensagem de exceção e à traço de pilha.

Código orquestrador não determinístico

O código do Orchestrator tem de ser determinístico. Código não determinístico causa falhas de repetição que resultam em comportamentos inesperados, ciclos infinitos ou erros. Não uses a hora atual, números aleatórios, GUIDs ou E/S (como chamadas HTTP) diretamente no código do Orchestrator. Use as alternativas fornecidas pelo contexto ou delegue para atividades.

// ❌ Wrong - non-deterministic
var now = DateTime.UtcNow;
var id = Guid.NewGuid();
var data = await httpClient.GetAsync("https://example.com/api");

// ✅ Correct - deterministic
var now = context.CurrentUtcDateTime;
var id = context.NewGuid();
var data = await context.CallActivityAsync<string>("FetchData");

Erros de serialização e desserialização

Os erros de serialização ocorrem quando os tipos usados para entradas, saídas ou resultados de atividade de orquestração não coincidem entre o sistema que chama e o sistema chamado. Estes erros podem aparecer como valores inesperados null , JsonException, ou falhas de type cast no seu histórico de orquestração.

Como diagnosticar:

  1. Abra o painel do Durable Task Scheduler e inspecione o histórico de orquestração. Veja os campos Input e Result para atividades que falharam.
  2. Verifique se o tipo esperado pelo orquestrador corresponde ao tipo devolvido pela atividade. Por exemplo, se a atividade devolver um string mas o orquestrador espera um int, a desserialização falha.
  3. Verifique se há tipos não serializáveis. Tipos personalizados que não podem ser serializados para JSON (por exemplo, tipos com referências circulares ou sem construtor padrão) falham silenciosamente ou lançam exceções.

Problema conhecido (Java): Passar um String diretamente para uma atividade pode resultar em cadeias com aspas duplas (por exemplo, "\"hello\"" em vez de "hello"). Este comportamento é um problema conhecido. Lança o resultado explicitamente ou usa objetos envoltório.

Sugestão

Use tipos de dados simples (strings, números, arrays e objetos simples ou POJOs/POCOs/dataclasses) para orquestração e entradas e saídas de atividade. Evite tipos complexos com lógica de serialização personalizada.

Questões de atividade

Atividade não encontrada

Se uma orquestração falhar com um erro de "atividade não encontrada", o nome da atividade registado com o trabalhador não corresponde ao nome usado no código de orquestração.

Em .NET, as atividades podem ser registadas pelo nome da classe ou usando o atributo [DurableTask] com geradores de código-fonte. Verifique se a classe de atividade está incluída no registo de trabalhadores:

builder.Services.AddDurableTaskWorker()
    .AddTasks(registry =>
    {
        registry.AddActivity<SayHello>();
    })
    .UseDurableTaskScheduler(connectionString);

Ao chamar a atividade a partir de um orquestrador, use o nome da classe:

string result = await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo");

Gestão de falhas de atividade

Quando uma atividade lança uma exceção, o orquestrador recebe um TaskFailedException (ou equivalente linguístico). Detete esta exceção e inspecione os detalhes internos do erro para encontrar a causa raiz. Em C#, use ex.FailureDetails para aceder ao tipo de erro e à mensagem, e IsCausedBy<T>() para verificar tipos específicos de exceção.

Para exemplos detalhados de gestão de erros e políticas de repetição em cada idioma, veja Gestão de erros e tentativas.

Problemas com o gRPC

Limite de tamanho de mensagem gRPC ultrapassado

Se vires um erro RESOURCE_EXHAUSTED ou message too large, uma orquestração ou atividade de entrada/saída excede o tamanho máximo de mensagem padrão do gRPC de 4 MB.

Atenuações:

  • Reduza o tamanho das entradas e saídas. Armazene grandes cargas úteis em armazenamento em nuvem, como o Armazenamento de Blobs do Azure, e apenas envie referências.
  • Divida grandes resultados de espalhamento em lotes menores processados através de suborquestrações.

Erros de cancelamento do fluxo durante o encerramento

Ao parar um trabalhador, pode ver CANCELLED: Cancelled on client erros. Estes erros são tipicamente inofensivos e ocorrem porque o fluxo gRPC entre o trabalhador e o agendador fecha durante o encerramento. Os SDKs .NET, Python e Java tratam estes erros internamente.

Em JavaScript, o SDK pode lançar Stream error Error: 1 CANCELLED: Cancelled on client ao chamar worker.stop(). Este erro é um problema conhecido. Inclua a chamada de paragem num try-catch se o erro afetar a lógica de desligamento:

try {
  await worker.stop();
} catch (error) {
  // Ignore stream cancellation errors during shutdown
  if (!error.message.includes("CANCELLED")) {
    throw error;
  }
}

Registo e diagnóstico

Configuração verbosa de registo

Aumente a verbosidade dos registos para obter mais detalhes sobre as operações do SDK, incluindo a comunicação gRPC e os eventos de repetição de orquestração.

No appsettings.json seu ficheiro de configuração de registo:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.DurableTask": "Debug"
    }
  }
}

Use registadores seguros para reprodução para evitar duplicações nas entradas durante a reexecução de orquestração.

public override async Task<string> RunAsync(
    TaskOrchestrationContext context, string input)
{
    ILogger logger = context.CreateReplaySafeLogger<MyOrchestrator>();
    logger.LogInformation("Processing input: {Input}", input);
    // ...
}

Integração do Application Insights

Para aplicações de produção, configure o Application Insights para recolher telemetria da sua aplicação Durable Task SDK. A abordagem de integração depende da sua plataforma de alojamento:

Plataforma de alojamento Instruções de configuração
Azure Container Apps Monitorize os registos no Azure Container Apps em Log Analytics
Serviço de Aplicações do Azure Ativar o registo de diagnóstico para aplicações em Serviço de Aplicações do Azure
Azure Kubernetes Service Monitor Azure Kubernetes Service

Para mais informações sobre diagnósticos, consulte Diagnósticos em SDKs de Tarefas Duradouras.

Questões específicas da língua

C#

Avisos de geradores de código interrompem builds

Se usares <TreatWarningsAsErrors>true</TreatWarningsAsErrors> no teu projeto, os geradores de código-fonte de Tarefas Duráveis podem gerar avisos (CS0419, VSTHRD105) que quebram a tua build. Suprima estes avisos específicos:

<PropertyGroup>
  <NoWarn>$(NoWarn);CS0419;VSTHRD105</NoWarn>
</PropertyGroup>

Este problema conhecido está a ser monitorizado em GitHub e será abordado numa próxima versão.

O analisador Roslyn insere loops de foreach

O analisador Roslyn da Durable Task pode lançar um ArgumentNullException quando o código lambda do orquestrador está dentro de um foreach loop. Este comportamento é um problema conhecido que não afeta o comportamento em tempo de execução. Atualize para a versão mais recente do pacote do analyzer para obter a correção.

Java

Erro de permissão negada do Gradle

No macOS ou Linux, a execução ./gradlew pode falhar com um erro de "permissão negada". Corrige este erro tornando o ficheiro executável:

chmod +x gradlew

OrchestratorBlockedException

Ocorre OrchestratorBlockedException quando o código do orquestrador executa uma operação de bloqueio que o SDK deteta como potencialmente não determinística. Esta exceção é uma salvaguarda para evitar que o código do orquestrador viole as restrições do código do orquestrador.

Causas comuns:

  • Chamar uma API externa bloqueante no código do Orquestrador.
  • Usando Thread.sleep() diretamente em vez de ctx.createTimer().
  • Executar I/O de ficheiros ou rede no código do orquestrador.

Transferir todas as operações de bloqueio ou I/O para atividades.

Python

A política de retentativas exige max_retry_interval

Quando configuras um retry_policy no Python, omitir o parâmetro max_retry_interval produz um erro que não indica claramente a causa. Especifique sempre: max_retry_interval

from datetime import timedelta
from durabletask import task

retry_policy = task.RetryPolicy(
    max_number_of_attempts=3,
    first_retry_interval=timedelta(seconds=5),
    max_retry_interval=timedelta(minutes=1),  # Required
)

Comportamento de exceções WhenAllTask

Quando utilizar o when_all para fazer várias tarefas em paralelo, se uma ou mais tarefas falharem, o comportamento das exceções pode não corresponder às expectativas. Apenas a primeira exceção é levantada, e as restantes exceções de tarefa podem ser perdidas. Inspecione os resultados de tarefas individuais se precisar de informação completa sobre erros:

tasks = [ctx.call_activity(process_item, input=item) for item in items]
try:
    results = yield task.when_all(tasks)
except TaskFailedError as e:
    # Only the first failure is raised
    # Check individual tasks for comprehensive error handling
    print(f"At least one task failed: {e}")

Obtenha suporte

Para perguntas e reportar bugs, abra uma questão no repositório GitHub para o SDK relevante. Quando reportar um bug, inclua:

  • IDs de instância de orquestração afetados
  • Intervalo temporal em UTC que mostra o problema
  • Nome da aplicação e região de implementação (se relevante)
  • Versão do SDK e plataforma de alojamento
  • Registos relevantes ou mensagens de erro
SDK Repositório GitHub
.NET Microsoft/durableTask-dotnet
Java Microsoft/DurableTask-Java
JavaScript Microsoft/DurableTask-JS
Python Microsoft/durableTask-Python