Résoudre les problèmes courants liés au Kit de développement logiciel (SDK) Durable Task

Cet article vous aide à diagnostiquer et à résoudre les problèmes courants lors de la création d’applications avec les kits SDK Durable Task portables. Recherchez votre scénario dans la liste suivante et suivez les étapes liées pour diagnostiquer et résoudre le problème.

Scénarios courants

Connexion et configuration

Orchestrations

Activités

gRPC

Journalisation et diagnostics

Spécifique à la langue

Ces kits SDK se connectent au serveur principal Durable Task Scheduler et s’exécutent sur n’importe quelle plateforme d’hébergement, notamment Azure Container Apps, Kubernetes et machines virtuelles.

Note

Ce guide couvre les kits SDK durables portables. Pour connaître les problèmes spécifiques au service Planificateur de tâches durables, consultez Résoudre les problèmes liés au planificateur de tâches durables. Pour connaître les problèmes spécifiques à l’extension Durable Functions, consultez Durable Functions guide de résolution des problèmes.

Conseil / Astuce

Le tableau de bord de surveillance du planificateur de tâches durables est utile pour inspecter l’état de l’orchestration, afficher l’historique d’exécution et identifier les échecs. Utilisez-le en même temps que ce guide pour accélérer la résolution des problèmes.

Rechercher votre problème

Message d’erreur ou symptôme Section
connection refused ou failed to connect au démarrage L’émulateur n’est pas en cours d’exécution ou est inaccessible
Erreurs d’analyse de chaîne de connexion ou erreurs d’authentification au démarrage Le format de chaîne de connexion est incorrect
Le Worker se connecte, mais les orchestrations ne démarrent pas. Le hub de tâches n’existe pas
erreurs 401 Unauthorized ou erreurs liées à l'identité ou au rôle sur Azure Échecs d'authentification basés sur l'identité sur Azure
Orchestration bloquée sur « En attente » L’orchestration est bloquée dans l’état « En attente »
Orchestration bloquée dans « En cours d’exécution » L’orchestration est bloquée dans l’état « En cours d’exécution »
Échecs de retransmission, boucles infinies ou comportement inattendu Code d’orchestrateur non déterministe
Erreurs d’incompatibilité de type ou de sérialisation JSON Erreurs de sérialisation et de désérialisation
activity not found Activité introuvable
RESOURCE_EXHAUSTED ou message too large Limite de taille de message gRPC dépassée
CANCELLED: Cancelled on client pendant l’arrêt Erreurs d’annulation de flux pendant l’arrêt
CS0419 / VSTHRD105 les avertissements provoquent l'échec de la construction Avertissements du générateur de source : provoquent l'échec des builds (C#)
OrchestratorBlockedException (Java) OrchestratorBlockedException (Java)
Erreur non utile lors de l’utilisation de retry_policy (Python) La politique de réessai nécessite max_retry_interval (Python)

Problèmes de connexion et de configuration

L’émulateur n’est pas en cours d’exécution ou est inaccessible

Si votre application échoue au démarrage avec une erreur de connexion telle que « connexion refusée » ou « échec de connexion », vérifiez que l’émulateur du planificateur de tâches durables est en cours d’exécution et accessible.

  1. Vérifiez que le conteneur Docker de l’émulateur est en cours d’exécution :

    docker ps | grep durabletask
    
  2. Vérifiez que les mappages de ports sont corrects. L’émulateur expose deux ports :

    • 8080 : point de terminaison gRPC (utilisé par votre application)
    • 8082 : interface utilisateur du tableau de bord

    Si vous utilisez un mappage de port personnalisé, mettez à jour votre chaîne de connexion pour qu'il corresponde au port hôte mappé au port de conteneur 8080.

  3. Testez la connectivité au point de terminaison gRPC :

    curl -v http://localhost:8080
    

    Un refus de connexion indique que le conteneur n’est pas en cours d’exécution ou que le mappage de port est incorrect.

Le format de chaîne de connexion est incorrect

Les erreurs de chaîne de connexion sont une cause courante des échecs de démarrage. Vérifiez que votre chaîne de connexion correspond au format attendu.

Développement local (émulateur) :

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

Azure (identité managée) :

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

Azure (identité managée affectée par l’utilisateur) :

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

Erreurs courantes :

  • Utilisation https de l’émulateur local (l’émulateur utilise http)
  • L’utilisation de http pour les points de terminaison Azure (Azure nécessite https)
  • Omettre le Authentication paramètre
  • Utilisation du port du tableau de bord (8082) au lieu du port gRPC (8080)

Le client ou le worker ne parvient pas à se connecter

Vérifiez que votre client et votre worker sont configurés avec le nom correct des chaîne de connexion et du hub de tâches.

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

Le hub de tâches n’existe pas

Si vos orchestrations ne démarrent pas ou si le worker se connecte mais ne traite aucun travail, il est possible que le hub de tâches n’existe pas sur le planificateur. L’émulateur crée généralement des hubs de tâches automatiquement à l’aide de la variable d’environnement DTS_TASK_HUB_NAMES .

Vérifiez que l’émulateur a été démarré avec le nom correct du hub de tâches :

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

Pour les planificateurs hébergés Azure, créez le hub de tâches à l’aide de la Azure CLI :

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

Échecs d’authentification basés sur l’identité sur Azure

Si votre application s’exécute localement, mais échoue lorsqu’elle est déployée sur Azure, le problème est probablement lié à l’authentification :

  1. Vérifiez que l’identité managée est affectée à votre application (affectée par le système ou affectée par l’utilisateur).
  2. Vérifiez que l’identité possède le rôle Durable Task Data Contributor sur la ressource du planificateur ou sur le hub de tâches concerné.
  3. Vérifiez que la chaîne de connexion utilise la valeur Authentication correcte (ManagedIdentity). Dans Python, passez une instance DefaultAzureCredential() comme paramètre token_credential au lieu d’utiliser un chaîne de connexion.
  4. Pour les identités attribuées par l’utilisateur, vérifiez que le ClientID dans la chaîne de connexion correspond à l’ID client de l’identité.

Pour obtenir des instructions détaillées, consultez Configurer l’identité managée pour Durable Task Scheduler.

Problèmes d’orchestration

L’orchestration est bloquée dans l'état « En attente »

Une orchestration au statut « En attente » indique qu’elle a été planifiée mais qu’aucun worker ne l’a encore prise en charge. Vérifiez les éléments suivants :

  • Le worker est en cours d’exécution. Vérifiez que votre processus de travail est en cours d’exécution et connecté au même hub de tâches que celui où l’orchestration a été planifiée.
  • Le nom du hub de tâches correspond bien. Vérifiez que le worker et le client utilisent tous deux le même nom de hub de tâches. Une incohérence entraîne l’interrogation d’un autre hub de tâches par le worker.
  • L’orchestrateur est enregistré. La fonction ou la classe d’orchestrateur référencée lors de la planification doit être enregistrée auprès du travailleur.

Vérifiez que la classe de l’orchestrateur est enregistrée auprès du worker lors du démarrage. Si vous utilisez des générateurs sources ([DurableTask] attribut), l’inscription est automatique. Sinon, inscrivez-vous manuellement :

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

L'orchestration est coincée à l'état "En cours d'exécution"

Une orchestration bloquée à l’état « En cours d’exécution » signifie généralement qu’elle attend une tâche qui n’est pas terminée. Pour diagnostiquer, ouvrez le tableau de bord du planificateur de tâches durables et inspectez l’historique d’exécution de l’orchestration. Recherchez le dernier événement terminé : l’événement suivant dans la séquence est celui qui bloque.

Causes courantes :

  • Activité non inscrite. L’orchestration appelle une activité dont le nom n’est pas enregistré auprès du worker. Le tableau de bord affiche un TaskScheduled événement sans TaskCompleted correspondant. Vérifiez que le nom de l’activité correspond entre votre code d’orchestrateur et l’inscription du worker (voir Activité introuvable).
  • En attente d’un événement externe. L’orchestration appelle waitForExternalEvent et l’événement n’a pas encore été déclenché. Le tableau de bord affiche un EventRaised événement attendu mais manquant. Vérifiez le nom de l’événement et que l’expéditeur cible l’ID d’instance d’orchestration approprié.
  • En attendant un minuteur durable. L’orchestration crée un minuteur qui n’a pas encore expiré. Le tableau de bord affiche un TimerCreated événement. Attendez que le minuteur se déclenche ou vérifiez si la durée du minuteur est plus longue que prévu.
  • L’activité lève une exception non gérée. Le tableau de bord affiche un TaskFailed événement. Vérifiez les détails de l'échec concernant le message d'exception et la trace de la pile.

Code d’orchestrateur non déterministe

Le code Orchestrator doit être déterministe. Le code non déterministe provoque des échecs de relecture qui entraînent un comportement inattendu, des boucles infinies ou des erreurs. N’utilisez pas l’heure actuelle, les nombres aléatoires, les GUID ou les E/S (comme les appels HTTP) directement dans le code d’orchestrateur. Utilisez les alternatives fournies par le contexte ou déléguez des activités.

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

Erreurs de sérialisation et de désérialisation

Des erreurs de sérialisation peuvent survenir lorsque les types utilisés pour les entrées ou sorties d’orchestration, ou pour les résultats d’activité, ne correspondent pas entre l’appelant et l’appelé. Ces erreurs peuvent apparaître sous forme de valeurs inattendues null, JsonException, ou d’échecs de conversion de type dans votre historique d'orchestration.

Comment diagnostiquer :

  1. Ouvrez le tableau de bord du planificateur de tâches durables et inspectez l’historique de l’orchestration. Regardez les champs Input et Result pour les activités qui ont échoué.
  2. Vérifiez que le type attendu par l’orchestrateur correspond au type retourné par l’activité. Par exemple, si une activité retourne un string, mais que l’orchestrateur attend un int, la désérialisation échoue.
  3. Vérifiez les types non sérialisables. Les types personnalisés qui ne peuvent pas être sérialisés au format JSON (par exemple, les types avec des références circulaires ou aucun constructeur par défaut) échouent en mode silencieux ou lèvent des exceptions.

Problème connu (Java) : Le passage d’un directement à une activité peut entraîner des chaînes de caractères entre guillemets doubles (par exemple, String au lieu de "\"hello\""). Ce comportement est un problème connu. Effectuez un cast explicite du résultat ou utilisez des objets encapsulants.

Conseil / Astuce

Utilisez des types de données simples (chaînes, nombres, tableaux et objets bruts ou objets POJOs/POC/dataclasses) pour l’orchestration et les entrées et sorties d’activité. Évitez les types complexes avec une logique de sérialisation personnalisée.

Problèmes d’activité

Activité introuvable

Si une orchestration échoue avec une erreur « activité introuvable », le nom de l'activité enregistré par le travailleur ne correspond pas au nom utilisé dans le code d'orchestration.

Dans .NET, les activités peuvent être inscrites par nom de classe ou à l’aide de l’attribut [DurableTask] avec des générateurs sources. Vérifiez que la classe d’activité est incluse dans l’enregistrement du travailleur.

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

Lorsque vous appelez l’activité à partir d’un orchestrateur, utilisez le nom de la classe :

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

Gestion des défaillances d’activité

Lorsqu’une activité génère une exception, l’orchestrateur reçoit une TaskFailedException (ou l’équivalent dans le langage utilisé). Interceptez cette exception et inspectez les détails de l’erreur interne pour trouver la cause racine. En C#, utilisez cette option ex.FailureDetails pour accéder au type d’erreur et au message, et IsCausedBy<T>() pour rechercher des types d’exceptions spécifiques.

Pour obtenir des exemples détaillés de gestion des erreurs et de stratégie de nouvelle tentative dans chaque langue, consultez Gestion des erreurs et nouvelles tentatives.

Problèmes gRPC

Limite de taille de message gRPC dépassée

Si vous voyez une erreur RESOURCE_EXHAUSTED ou message too large, cela signifie qu'une orchestration ou une entrée/sortie d’activité dépasse la taille maximale par défaut de message gRPC, qui est de 4 MB.

Atténuations:

  • Réduisez la taille des entrées et des sorties. Stockez des charges utiles volumineuses dans un stockage externe, comme Stockage Blob Azure, et transmettez uniquement des références.
  • Divisez les résultats volumineux issus d’un fan-out en lots plus petits traités via des sous-orchestrations.

Erreurs d’annulation de flux de données pendant l’arrêt

Lors de l’arrêt d’un worker, des erreurs peuvent s’afficher CANCELLED: Cancelled on client . Ces erreurs sont généralement sans gravité et surviennent parce que le flux gRPC entre le worker et le planificateur est fermé pendant l’arrêt. Les kits sdk .NET, Python et Java gèrent ces erreurs en interne.

Dans JavaScript, le SDK peut générer Stream error Error: 1 CANCELLED: Cancelled on client lors de l’appel worker.stop(). Cette erreur est un problème connu. Encapsulez l’appel d’arrêt dans un bloc try/catch si l’erreur perturbe votre logique d’arrêt :

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

Journalisation et diagnostics

Configuration détaillée de la journalisation

Augmentez le niveau de verbosité des journaux pour obtenir davantage de détails sur les opérations du SDK, notamment la communication gRPC et les événements de relecture des orchestrations.

Dans votre fichier de configuration appsettings.json ou de journalisation :

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

Utilisez des enregistreurs compatibles avec la relecture afin d’éviter les entrées de journal en double lors de la relecture d’orchestration :

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

Intégration d’Application Insights

Pour les applications de production, configurez Application Insights pour collecter les données de télémétrie à partir de votre application sdk Durable Task. L’approche d’intégration dépend de votre plateforme d’hébergement :

Plateforme d’hébergement Instructions d’installation
Azure Container Apps (Applications de Conteneur Azure) Surveiller les journaux dans Azure Container Apps avec Log Analytics
Azure App Service Activer la journalisation des diagnostics pour les applications dans Azure App Service
Azure Kubernetes Service Surveiller le service Azure Kubernetes

Pour plus d’informations relatives aux diagnostics, consultez la section Diagnostics des SDK Durable Task.

Problèmes spécifiques au langage

C#

Les avertissements des générateurs de source provoquent des échecs de compilation

Si vous utilisez <TreatWarningsAsErrors>true</TreatWarningsAsErrors> dans votre projet, les générateurs de sources durables de tâche peuvent générer des avertissements (CS0419, VSTHRD105) qui interrompent votre build. Supprimez ces avertissements spécifiques :

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

Ce problème connu est suivi sur GitHub et sera résolu dans une prochaine version.

L’analyseur Roslyn génère une erreur dans les boucles foreach

L’analyseur Roslyn de Durable Task peut générer une ArgumentNullException lorsque le code lambda de l’orchestrateur se trouve dans une boucle foreach. Ce comportement est un problème connu qui n’affecte pas le comportement d’exécution. Effectuez une mise à jour vers la dernière version du package d’analyseur pour obtenir le correctif.

Java

Erreur de permission refusée par Gradle

Sur macOS ou Linux, l’exécution ./gradlew peut échouer avec une erreur « autorisation refusée ». Corrigez cette erreur en rendant le fichier exécutable :

chmod +x gradlew

OrchestratorBlockedException

Le OrchestratorBlockedException se produit quand le code d’orchestrateur effectue une opération bloquante détectée par le SDK comme potentiellement non déterministe. Cette exception est une protection pour empêcher le code d’orchestrateur de violer les contraintes de code d’orchestrateur.

Causes courantes :

  • Appel d’une API externe bloquante dans le code d’orchestrateur.
  • Utilisation Thread.sleep() directe au lieu de ctx.createTimer().
  • Effectuer des opérations d’E/S de fichiers ou réseau dans le code de l’orchestrateur.

Déplacez toutes les opérations de blocage ou d’E/S dans les activités.

Python

La stratégie de nouvelle tentative nécessite le max_retry_interval

Lorsque vous configurez un retry_policy dans Python, l'omission du paramètre max_retry_interval génère une erreur qui n'indique pas clairement la cause. Toujours spécifier 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
)

Comportement de l’exception WhenAllTask

Lorsque vous utilisez when_all pour exécuter plusieurs tâches en parallèle, si une ou plusieurs tâches échouent, le comportement d’exception peut ne pas correspondre aux attentes. Seule la première exception est levée et les exceptions de tâche restantes peuvent être perdues. Inspectez les résultats des tâches individuelles si vous avez besoin d’informations d’erreur complètes :

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

Obtenir du support

Pour les questions et la création de rapports de bogues, ouvrez un problème dans le dépôt GitHub pour le Kit de développement logiciel (SDK) approprié. Lorsque vous signalez un bogue, incluez :

  • ID d'instances d'orchestration affectées
  • Intervalle de temps utc montrant le problème
  • Nom de l’application et région de déploiement (le cas échéant)
  • Version et plateforme d’hébergement du Kit de développement logiciel (SDK)
  • Journaux d’activité ou messages d’erreur pertinents
SDK dépôt GitHub
.NET microsoft/durabletask-dotnet
Java microsoft/durabletask-java
JavaScript microsoft/durabletask-js
Python microsoft/durabletask-python