Solución de problemas comunes del SDK de Durable Task

Este artículo le ayuda a diagnosticar y corregir problemas comunes al compilar aplicaciones con los SDK portátiles de Durable Task. Busque el escenario en la lista siguiente y siga los pasos vinculados para diagnosticar y resolver el problema.

Escenarios comunes

Conexión y configuración

Orquestaciones

Actividades

gRPC

Registro y diagnóstico

Específico del idioma

Estos SDK se conectan al back-end del programador de tareas Durable y se ejecutan en cualquier plataforma de hospedaje, incluidos Azure Container Apps, Kubernetes y vm.

Nota:

En esta guía se describen los SDK portátiles de Durable Task. Para ver problemas específicos del servicio Programador de tareas durables, consulte Solución de problemas del programador de tareas durables. Para ver problemas específicos de la extensión de Durable Functions, consulte Durable Functions guía de solución de problemas.

Sugerencia

El panel de monitoreo del programador de tareas duraderas es útil para inspeccionar el estado de la orquestación, ver el historial de ejecución e identificar fallos. Úselo junto con esta guía para acelerar la solución de problemas.

Encuentra tu problema

Mensaje de error o síntoma Section
connection refused o failed to connect en el inicio El emulador no se está ejecutando o no es accesible
Errores en el análisis de la cadena de conexión o errores de autenticación al inicio El formato de cadena de conexión es incorrecto
El worker se conecta, pero las orquestaciones no se inician El centro de tareas no existe
errores de 401 Unauthorized o identity/role en Azure Errores de autenticación basados en identidades en Azure
Orquestación bloqueada en "Pendiente" La orquestación está bloqueada en el estado "Pendiente"
Orquestación bloqueada en "En ejecución" La orquestación está bloqueada en el estado "En ejecución"
Errores de reproducción, bucles infinitos o comportamiento inesperado Código de orquestador no determinista
Errores de incompatibilidad de tipos o de serialización JSON Errores de serialización y deserialización
activity not found Actividad no encontrada
RESOURCE_EXHAUSTED o message too large Se superó el límite de tamaño del mensaje gRPC
CANCELLED: Cancelled on client durante el apagado Errores de cancelación de flujos durante el apagado
CS0419 / VSTHRD105 advertencias interrumpen la construcción Advertencias del generador de origen interrumpen las compilaciones (C#)
OrchestratorBlockedException (Java) OrchestratorBlockedException (Java)
Error no útil al usar retry_policy (Python) La política de reintento requiere max_retry_interval (Python)

Problemas de conexión y configuración

El emulador no se está ejecutando o no es accesible

Si se produce un error en el inicio de la aplicación con un error de conexión como "conexión rechazada" o "no se pudo conectar", compruebe que el emulador del Programador de tareas durable está en ejecución y accesible.

  1. Compruebe que el contenedor de Docker del emulador se está ejecutando:

    docker ps | grep durabletask
    
  2. Compruebe que las asignaciones de puertos son correctas. El emulador expone dos puertos:

    • 8080: punto de conexión gRPC (usado por la aplicación)
    • 8082: interfaz de usuario del panel

    Si usa una asignación de puertos personalizada, actualice el cadena de conexión para que coincida con el puerto host asignado al puerto de contenedor 8080.

  3. Pruebe la conectividad con el punto de conexión gRPC:

    curl -v http://localhost:8080
    

    Una negativa de conexión indica que el contenedor no se está ejecutando o que la asignación de puertos es incorrecta.

El formato de cadena de conexión es incorrecto

Los errores de cadena de conexión son una causa común de errores de inicio. Compruebe que el cadena de conexión coincide con el formato esperado.

Desarrollo local (emulador):

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

Azure (identidad administrada):

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

Azure (identidad administrada asignada por el usuario):

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

Errores comunes:

  • Uso https para el emulador local (el emulador usa http)
  • Usar http para puntos de conexión de Azure (Azure requiere https)
  • Omitir el Authentication parámetro
  • Uso del puerto del panel (8082) en lugar del puerto gRPC (8080)

El cliente o el trabajador no se pueden conectar

Compruebe que su cliente y trabajador están configurados con la cadena de conexión y el nombre del centro de tareas correctos.

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

El centro de tareas no existe

Si las orquestaciones no se inician o el trabajador se conecta pero no procesa el trabajo, es posible que el centro de tareas no exista en el planificador. Normalmente, el emulador crea centros de tareas automáticamente mediante la variable de DTS_TASK_HUB_NAMES entorno.

Compruebe que el emulador se inició con el nombre correcto del centro de tareas:

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

Para los programadores o planificadores hospedados en Azure, cree el centro de tareas mediante la CLI de Azure.

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

Errores de autenticación basados en identidades en Azure

Si la aplicación se ejecuta localmente, pero se produce un error cuando se implementa en Azure, es probable que el problema esté relacionado con la autenticación:

  1. Compruebe que la identidad administrada está asignada a la aplicación (asignada por el sistema o asignada por el usuario).
  2. Compruebe que la identidad tiene el rol de colaborador de datos de Durable Task en el recurso del programador o en un centro de tareas específico.
  3. Asegúrese de que el cadena de conexión usa el valor de Authentication correcto (ManagedIdentity). En Python, pasa una instancia DefaultAzureCredential() como parámetro token_credential en lugar de usar una cadena de conexión.
  4. En el caso de las identidades asignadas por el usuario, compruebe que el ClientID en el cadena de conexión coincide con el identificador de cliente de la identidad.

Para obtener instrucciones detalladas, consulte Configuración de la identidad administrada para Durable Task Scheduler.

Problemas de orquestación

La orquestación está bloqueada en el estado "Pendiente"

Una orquestación en estado "Pendiente" indica que está programada, pero un trabajo aún no la ha seleccionado. Compruebe los siguientes elementos:

  • El trabajo se está ejecutando. Asegúrese de que el proceso de trabajo esté en funcionamiento y conectado al mismo centro de tareas en el que se programó la orquestación.
  • El nombre del centro de tareas coincide. Compruebe que el trabajador y el cliente hacen referencia al mismo nombre del hub de tareas. Una falta de coincidencia hace que el trabajador sondee un centro de tareas diferente.
  • Orchestrator está registrado. La función o clase orquestadora a la que se hace referencia al programar debe estar registrada con el trabajador.

Compruebe que la clase de orquestador está registrada con el trabajo durante el inicio. Si usa generadores de origen ([DurableTask] atributo), el registro es automático. De lo contrario, registre manualmente:

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

La orquestación está bloqueada en el estado "En ejecución"

Una orquestación bloqueada en "En ejecución" normalmente significa que está esperando una tarea que no se ha completado. Para diagnosticar, abra el panel del Programador de Tareas Duraderas e inspeccione el historial de ejecución de la orquestación. Busque el último evento completado, ya que el siguiente evento de la secuencia es el que está causando el bloqueo.

Causas comunes:

  • Actividad no registrada. La orquestación llama a un nombre de actividad que no está registrado con el trabajo. El panel muestra un TaskScheduled evento sin el correspondiente TaskCompleted. Verifique que el nombre de la actividad coincida entre el código del orquestador y el registro de trabajador (consulte Actividad no encontrada).
  • Esperando un evento externo. La orquestación llama a waitForExternalEvent y el evento todavía no se desencadena. El panel muestra que se espera un evento EventRaised, pero no se encuentra. Compruebe el nombre del evento y que el remitente tenga como destino el identificador de instancia de orquestación correcto.
  • Esperando un temporizador fiable. La orquestación crea un temporizador que aún no ha expirado. El panel muestra un evento TimerCreated. Espere a que se active el temporizador o compruebe si la duración del temporizador es mayor de lo esperado.
  • La actividad produce una excepción no controlada. El panel muestra un evento TaskFailed. Compruebe los detalles del error para el mensaje de excepción y el seguimiento de la pila.

Código de orquestador no determinista

El código de Orchestrator debe ser determinista. El código no determinista provoca errores de reproducción que producen un comportamiento inesperado, bucles infinitos o errores. No use la hora actual, los números aleatorios, los GUID o la E/S (como las llamadas HTTP) directamente en el código del orquestador. Usa las alternativas proporcionadas por el contexto o delega en actividades.

// ❌ 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");

Errores de serialización y deserialización

Los errores de serialización se producen cuando los tipos usados para las entradas, salidas o resultados de actividad de la orquestación no coinciden entre el autor de la llamada y el destinatario. Estos errores pueden aparecer como valores inesperados null, JsonException, o errores de conversión de tipos en el historial de orquestaciones.

Cómo realizar el diagnóstico:

  1. Abra el panel del Programador de tareas duraderas e inspeccione el historial de orquestación. Mira los campos Input y Result para las actividades que fallaron.
  2. Compruebe que el tipo esperado por el orquestador coincide con el tipo devuelto por la actividad. Por ejemplo, si la actividad devuelve un string pero el orquestador espera un int, se produce un error en la deserialización.
  3. Compruebe si hay tipos no serializables. Los tipos personalizados que no se pueden serializar en JSON (por ejemplo, tipos con referencias circulares o sin constructor predeterminado) producen errores en modo silencioso o inician excepciones.

Known issue (Java): pasar un String directamente a una actividad puede dar lugar a cadenas entre comillas dobles (por ejemplo, "\"hello\"" en lugar de "hello"). Este comportamiento es un problema conocido. Convierta el resultado explícitamente o use objetos contenedores.

Sugerencia

Use tipos de datos simples (cadenas, números, matrices y objetos sin formato o POJOs/POCOs/dataclasses) para las entradas y salidas de orquestación y actividad. Evite tipos complejos con lógica de serialización personalizada.

Problemas de actividad

Actividad no encontrada

Si una orquestación falla con un error de "actividad no encontrada", significa que el nombre de la actividad registrado con el trabajo no coincide con el nombre utilizado en el código de orquestación.

En .NET, las actividades se pueden registrar por nombre de clase o mediante el atributo [DurableTask] con generadores de origen. Compruebe que la clase de actividad se incluye en el registro de trabajo:

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

Al llamar a la actividad desde un orquestador, utilice el nombre de la clase:

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

Manejo de fallos de actividad

Cuando una actividad lanza una excepción, el orquestador recibe un TaskFailedException (o su equivalente en el idioma). Capture esta excepción e inspeccione los detalles del error interno para encontrar la causa principal. En C#, use ex.FailureDetails para acceder al tipo de error y el mensaje, y IsCausedBy<T>() para comprobar si hay tipos de excepciones específicos.

Para obtener ejemplos detallados de directivas de control de errores y reintento en cada idioma, consulte Control de errores y reintentos.

Problemas de gRPC

Se superó el límite de tamaño del mensaje gRPC

Si ve un error en RESOURCE_EXHAUSTED o message too large, una entrada o salida de actividad supera el tamaño máximo de mensaje predeterminado de gRPC de 4 MB.

Mitigaciones:

  • Reduzca el tamaño de las entradas y salidas. Almacene cargas grandes en el almacenamiento externo, como Azure Blob Storage, y pase solo referencias.
  • Divida los resultados grandes de distribución ramificada en lotes más pequeños que se procesen a través de suborquestaciones.

Errores de cancelación de flujos durante el apagado

Al detener un trabajador, puede ver CANCELLED: Cancelled on client errores. Estos errores suelen ser inofensivos y se producen porque la secuencia de gRPC entre el trabajador y el programador se cierra durante el apagado. Los SDK de .NET, Python y Java controlan estos errores internamente.

En JavaScript, el SDK podría lanzar Stream error Error: 1 CANCELLED: Cancelled on client al llamar a worker.stop(). Este error es un problema conocido. Encapsule la llamada de parada en un try-catch si el error afecta a la lógica de cierre:

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

Registro y diagnóstico

Configuración del registro detallado

Aumente el detalle del registro para obtener más detalles sobre las operaciones del SDK, incluidas la comunicación a través de gRPC y los eventos de reproducción de orquestación.

En su appsettings.json o archivo de configuración de registro:

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

Use registradores seguros para la reproducción para evitar entradas de registro duplicadas durante la reproducción de la orquestación:

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

Integración de Application Insights

En el caso de las aplicaciones de producción, configure Application Insights para recopilar datos de telemetría de la aplicación del SDK de Durable Task. El enfoque de integración depende de la plataforma de hospedaje:

Plataforma de hospedaje Instrucciones de instalación
Azure Container Apps (Aplicaciones de Contenedores de Azure) Monitoriza registros en Azure Container Apps con Log Analytics
Azure App Service Habilitación del registro de diagnóstico para aplicaciones en Azure App Service
Azure Kubernetes Service Supervisión de Azure Kubernetes Service

Para obtener más información sobre los diagnósticos, consulte Diagnósticos en SDK de Durable Task.

Problemas específicos del idioma

C#

Las advertencias del generador de código fuente rompen las compilaciones

Si usa <TreatWarningsAsErrors>true</TreatWarningsAsErrors> en el proyecto, los generadores de origen de Durable Task podrían generar advertencias (CS0419, VSTHRD105) que interrumpen la compilación. Suprima estas advertencias específicas:

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

Este problema conocido se está siguiendo en GitHub y se abordará en una próxima versión.

El analizador de Roslyn genera errores en bucles foreach

El analizador Roslyn de Durable Task podría provocar una ArgumentNullException cuando el código lambda del orquestador está dentro de un bucle foreach. Este comportamiento es un problema conocido que no afecta al comportamiento en tiempo de ejecución. Actualice a la versión más reciente del paquete del analizador para obtener la corrección.

Java

Error de permiso denegado de Gradle

En macOS o Linux, la ejecución ./gradlew podría producir un error de "permiso denegado". Corrija este error haciendo que el archivo sea ejecutable:

chmod +x gradlew

OrchestratorBlockedException

OrchestratorBlockedException Se produce cuando el código de orquestador realiza una operación de bloqueo que el SDK detecta como potencialmente no determinista. Esta excepción es una protección para evitar que el código de orquestador infrinjan las restricciones de código del orquestador.

Causas comunes:

  • Llamar a una API externa bloqueante en el código del orquestador.
  • Usar Thread.sleep() directamente en lugar de ctx.createTimer().
  • Realización de entrada/salida de archivos o red en el código del orquestador.

Mueva todas las operaciones de bloqueo o de E/S a actividades.

Python

La política de reintento requiere max_retry_interval

Al configurar un retry_policy en Python, al omitir el parámetro max_retry_interval se produce un error que no indica claramente la causa. max_retry_intervalEspecifique siempre :

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
)

Comportamiento de excepción WhenAllTask

Cuando se usa when_all para ejecutar varias tareas en paralelo, si se produce un error en una o varias tareas, es posible que el comportamiento de la excepción no coincida con las expectativas. Solo se produce la primera excepción y se pueden perder las excepciones de tarea restantes. Inspeccione los resultados de las tareas individuales si necesita información de error completa:

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}")

Obtener soporte técnico

Para preguntas e informes de errores, abra un problema en el repositorio de GitHub para el SDK correspondiente. Al notificar un error, incluya:

  • Identificadores de instancia de orquestación afectados
  • Intervalo de tiempo en UTC que muestra el problema
  • Nombre de aplicación e región de implementación (si procede)
  • Versión del SDK y plataforma de hospedaje
  • Registros relevantes o mensajes de error
SDK Repositorio de GitHub
.NET microsoft/durabletask-dotnet
Java microsoft/durabletask-java
JavaScript microsoft/durabletask-js
Python microsoft/durabletask-python