Risolvere i problemi comuni di Durable Task SDK

Questo articolo consente di diagnosticare e risolvere i problemi comuni durante la compilazione di applicazioni con gli SDK di Durable Task portabili. Questi SDK si connettono al back-end Durable Task Scheduler ed eseguiti in qualsiasi piattaforma di hosting, tra cui App contenitore di Azure, Kubernetes e macchine virtuali. Per problemi specifici del servizio Durable Task Scheduler, vedere Risoluzione dei problemi del Durable Task Scheduler. Per i problemi di Durable Functions, vedere la guida alla risoluzione dei problemi di Durable Functions.

Suggerimento

Il dashboard di monitoraggio di Durable Task Scheduler è utile per esaminare lo stato dell'orchestrazione, visualizzare la cronologia di esecuzione e identificare gli errori. Usarlo insieme a questa guida per velocizzare la risoluzione dei problemi.

Trovare il problema

Messaggio di errore o sintomo Sezione
connection refused o failed to connect all'avvio L'emulatore non è in esecuzione o non è raggiungibile
Errori di analisi della stringa di connessione o errori di autenticazione all'avvio Il formato della stringa di connessione non è corretto
Il worker si connette ma le orchestrazioni non vengono avviate L'hub attività non esiste
401 Unauthorized o errori di identità/ruolo in Azure Fallimenti dell'autenticazione basata su identità in Azure
Orchestrazione bloccata in "In sospeso" L'orchestrazione è bloccata nello stato "In sospeso"
Orchestrazione bloccata su "In esecuzione" L'orchestrazione è bloccata nello stato "In esecuzione"
Errori di riproduzione, cicli infiniti o comportamento imprevisto Codice dell'agente di orchestrazione non deterministico
Errori di serializzazione JSON o mancata corrispondenza del tipo Errori di serializzazione e deserializzazione
activity not found Attività non trovata
RESOURCE_EXHAUSTED oppure message too large Limite di dimensioni dei messaggi gRPC superato
CANCELLED: Cancelled on client durante l'arresto Errori di cancellazione del flusso durante il 'shutdown'
CS0419 / VSTHRD105 avvisi interrompono il build Gli avvisi del generatore di origine interrompono le compilazioni (C#)
OrchestratorBlockedException (Java) OrchestratorBlockedException (Java)
Errore non utile quando si usa retry_policy (Python) La politica di Retry richiede max_retry_interval (Python)

Problemi di connessione e configurazione

L'emulatore non è in esecuzione o non è raggiungibile

Se la tua app non si avvia con un errore di connessione come "connessione rifiutata" o "non è riuscita a connettersi", verifica che l'emulatore del Durable Task Scheduler sia in esecuzione e accessibile.

  1. Verificare che il contenitore Docker dell'emulatore sia in esecuzione:

    docker ps | grep durabletask
    
  2. Verificare le mappature corrette delle porte. L'emulatore espone due porte:

    • 8080- endpoint gRPC (usato dall'app)
    • 8082- Interfaccia utente del dashboard

    Se si usa un mapping di porte personalizzato, aggiornare il stringa di connessione in modo che corrisponda alla porta host mappata alla porta del contenitore 8080.

  3. Testare la connettività all'endpoint gRPC:

    curl -v http://localhost:8080
    

    Il rifiuto di connessione indica che il contenitore non è in esecuzione o che la mappatura delle porte non è corretta.

Il formato della stringa di connessione non è corretto

Gli errori delle stringhe di connessione sono una causa comune di errori di avvio. Verificare che il stringa di connessione corrisponda al formato previsto.

Sviluppo locale (emulatore):

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

Azure (identità gestita):

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

Azure (identità gestita assegnata dall'utente):

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

Errori comuni:

  • Uso https dell'emulatore locale (l'emulatore usa http)
  • L'uso di http per gli endpoint di Azure (Azure richiede https)
  • Omissione del Authentication parametro
  • Uso della porta del dashboard (8082) anziché della porta gRPC (8080)

Il client o il lavoratore non riesce a connettersi

Se il client o il lavoratore non riesce a connettersi, verificare quanto segue:

  • La stringa di connessione corrisponde al formato previsto visualizzato in Formato stringa di connessione non corretta.
  • Il nome dell'hub attività è lo stesso sia per il client che per il worker.
  • Endpoint URL usa http per l'emulatore locale e https per Azure.

Per esempi di configurazione completi in ogni lingua, vedere Creare un'app con GLI SDK per attività permanenti.

L'hub delle attività non esiste

Se le orchestrazioni non riescono ad avviarsi o il worker si connette ma non elabora il lavoro, è possibile che l'hub di attività non esista nell'utilità di pianificazione. L'emulatore in genere crea automaticamente hub di attività usando la variabile DTS_TASK_HUB_NAMES d'ambiente.

Verificare che l'emulatore sia stato avviato con il nome corretto dell'hub delle attività.

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

Per le utilità di pianificazione ospitate su Azure, creare l'hub delle attività usando l'interfaccia interfaccia della riga di comando di Azure.

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

Errori di autenticazione basati sull'identità in Azure

Se l'app viene eseguita in locale ma non riesce quando viene distribuita in Azure, è probabile che il problema sia correlato all'autenticazione:

  1. Verificare che l'identità gestita sia assegnata all'app (assegnata dal sistema o assegnata dall'utente).
  2. Verificare che l'identità disponga del ruolo Collaboratore dati delle attività durevoli nella risorsa dell'utilità di pianificazione o in un hub attività specifico.
  3. Assicurarsi che la stringa di connessione utilizzi il valore Authentication corretto (ManagedIdentity). In Python, passare un'istanza di DefaultAzureCredential() come parametro token_credential anziché usare una stringa di connessione.
  4. Per le identità assegnate dall'utente, verificare che il ClientID nella stringa di connessione corrisponda all'ID client dell'identità.

Per istruzioni dettagliate, vedere Accesso basato su identità per Durable Task Scheduler.

Problemi di orchestrazione

L'orchestrazione è bloccata nello stato "In sospeso"

Un'orchestrazione nello stato "In sospeso" indica che è stata pianificata, ma un worker non l'ha prelevata. Controllare gli elementi seguenti:

  • Worker in esecuzione. Verificare che il processo di lavoro sia in esecuzione e connesso allo stesso hub attività in cui è stata pianificata l'orchestrazione.
  • Il nome dell'hub attività corrisponde. Verificare che il lavoratore e il client facciano entrambi riferimento allo stesso task hub name. Una mancata corrispondenza fa sì che il worker esegua il polling di un hub attività diverso.
  • Orchestrator è registrato. La funzione o la classe dell'agente di orchestrazione a cui viene fatto riferimento durante la pianificazione deve essere registrata con il worker.

Verificare che la classe di orchestrazione sia registrata con il worker all'avvio. Se si usano generatori di origine ([DurableTask] attributo), la registrazione è automatica. In caso contrario, registrare manualmente:

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

L'orchestrazione è bloccata nello stato "In esecuzione"

Un'orchestrazione bloccata in "In esecuzione" significa in genere che è in attesa di un'attività che non è stata completata. Per effettuare la diagnosi, aprire il dashboard del Programma di Pianificazione Attività Permanenti ed esaminare la cronologia delle esecuzioni dell'orchestrazione. Cercare l'ultimo evento completato: l'evento successivo nella sequenza è quello che impedisce il progresso.

Cause comuni:

  • Attività non registrata. L'orchestrazione chiama un nome di attività non registrato con il worker. Dashboard mostra un TaskScheduled evento senza un corrispondente TaskCompleted. Verificare che il nome dell'attività corrisponda tra il codice dell'orchestratore e la registrazione del lavoratore (vedere Attività non trovata).
  • In attesa di un evento esterno. L'orchestrazione chiama waitForExternalEvent ma l'evento non è ancora stato attivato. Il dashboard mostra un EventRaised evento previsto ma mancante. Verificare il nome dell'evento e assicurarsi che il mittente stia indirizzando correttamente l'ID istanza di orchestrazione.
  • In attesa di un timer durevole. L'orchestrazione crea un timer che non è ancora scaduto. Il dashboard mostra un TimerCreated evento. Attendere che il timer venga attivato o controllare se la durata del timer è più lunga del previsto.
  • L'attività genera un'eccezione non gestita. Il dashboard mostra un TaskFailed evento. Controllare i dettagli dell'errore per il messaggio di eccezione e l'analisi dello stack.

Codice dell'agente di orchestrazione non deterministico

Il codice dell'agente di orchestrazione deve essere deterministico. Il codice non deterministico causa errori di riproduzione che causano comportamenti imprevisti, cicli infiniti o errori. Non usare l'ora corrente, i numeri casuali, i GUID o le operazioni di I/O (come le chiamate HTTP) direttamente nel codice dell'agente di orchestrazione. Usare le alternative fornite dal contesto o delegare alle attività.

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

Errori di serializzazione e deserializzazione

Gli errori di serializzazione si verificano quando i tipi usati per gli input di orchestrazione, gli output o i risultati dell'attività non corrispondono tra il chiamante e il chiamato. Questi errori possono apparire come valori imprevisti null, JsonException o errori di conversione di tipo nella cronologia dell'orchestrazione.

Come effettuare la diagnosi:

  1. Aprire il Dashboard del Pianificatore di Attività Durabile ed esaminare la cronologia dell'orchestrazione. Osserva i campi Input e le attività Result che hanno avuto esito negativo.
  2. Verificare che il tipo previsto dall'orchestratore corrisponda al tipo restituito dall'attività. Ad esempio, se l'attività restituisce un string ma l'agente di orchestrazione prevede un int, la deserializzazione fallisce.
  3. Verificare la presenza di tipi non serializzabili. I tipi personalizzati che non possono essere serializzati in JSON (ad esempio, i tipi con riferimenti circolari o nessun costruttore predefinito) hanno esito negativo in modo invisibile all'utente o generano eccezioni.

Problema noto (Java): Il passaggio di un String direttamente a un'attività può comportare stringhe tra virgolette doppie (ad esempio, "\"hello\"" anziché "hello"). Questo comportamento è un problema noto. Effettua il cast del risultato in modo esplicito o utilizza oggetti wrapper.

Suggerimento

Usare tipi di dati semplici (stringhe, numeri, array e oggetti semplici o POJOs/POCOs/dataclasses) per l'orchestrazione e per gli input e output delle attività. Evitare tipi complessi con logica di serializzazione personalizzata.

Problemi di attività

Attività non trovata

Se un'orchestrazione non riesce con un errore "attività non trovata", il nome dell'attività registrato con il worker non corrisponde al nome usato nel codice di orchestrazione.

In .NET le attività possono essere registrate in base al nome della classe o usando l'attributo [DurableTask] con generatori di origine. Verificare che la classe di attività sia inclusa nella registrazione del lavoratore.

builder.Services.AddDurableTaskWorker(builder =>
{
    builder.AddTasks(tasks =>
    {
        tasks.AddActivity<SayHello>();
    });
});

Quando si chiama l'attività da un orchestratore, usare il nome della classe:

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

Gestione dei fallimenti delle attività

Quando un'attività genera un'eccezione, l'orchestratore riceve un TaskFailedException (o equivalente nella lingua). Intercettare questa eccezione ed esaminare i dettagli dell'errore interno per trovare la causa radice. In C# usare ex.FailureDetails per accedere al tipo di errore e al messaggio e IsCausedBy<T>() per verificare la presenza di tipi di eccezione specifici.

Per esempi dettagliati di criteri di gestione e ripetizione degli errori in ogni lingua, vedere Gestione degli errori e tentativi.

Problemi di gRPC

Limite di dimensioni dei messaggi gRPC superato

Se vedi un RESOURCE_EXHAUSTED o message too large errore, un input/output di orchestrazione o attività supera la dimensione massima predefinita di 4 MB del messaggio gRPC.

Mitigazioni:

  • Ridurre le dimensioni degli input e degli output. Archiviare payload di grandi dimensioni nell'archiviazione esterna, ad esempio Archiviazione BLOB di Azure e passare solo riferimenti.
  • Suddividere i risultati di fan-out di grandi dimensioni in batch più piccoli elaborati tramite orchestrazioni secondarie.

Errori di annullamento dello stream durante l'arresto

Quando si arresta un ruolo di lavoro, potrebbero verificarsi CANCELLED: Cancelled on client errori. Questi errori sono in genere innocui e si verificano perché il flusso gRPC tra il worker e l'utilità di pianificazione si chiude durante l'arresto. Gli SDK .NET, Python e Java gestiscono questi errori internamente.

In JavaScript, l'SDK potrebbe generare quando Stream error Error: 1 CANCELLED: Cancelled on client si chiama worker.stop(). Questo errore è un problema noto. Eseguire il wrapping della chiamata di arresto in un try-catch se l'errore influisce sulla logica di arresto:

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

Registrazione e diagnostica

Configurazione della registrazione verbosa

Aumentare il livello di dettaglio del log per ottenere altri dettagli sulle operazioni dell'SDK, incluse le comunicazioni gRPC e gli eventi di riproduzione dell'orchestrazione.

Nel file di configurazione appsettings.json o di log:

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

Usare logger sicuri per la riproduzione per evitare voci di log duplicate durante la riproduzione dell'orchestrazione:

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

Integrazione con Application Insights

Per le applicazioni di produzione, configurare Application Insights per raccogliere dati di telemetria dall'applicazione Durable Task SDK. L'approccio di integrazione dipende dalla piattaforma di hosting:

Piattaforma di hosting Istruzioni di installazione
App contenitore di Azure Monitorare i log nelle App contenitore di Azure con Log Analytics
Servizio app di Azure Abilitare la registrazione diagnostica per le app in Servizio app di Azure
Servizio Azure Kubernetes Monitorare il servizio Azure Kubernetes

Per altre informazioni sulla diagnostica, vedere Diagnostics in Durable Task SDK .For more information about diagnostics, see Diagnostics in Durable Task SDK.

Problemi specifici della lingua

C#

Gli avvisi dei generatori di codice sorgente interrompono i build

Se si usa <TreatWarningsAsErrors>true</TreatWarningsAsErrors> nel progetto, i generatori di origini Durable Task potrebbero generare avvisi (CS0419, VSTHRD105) che interrompono la compilazione. Eliminare questi avvisi specifici:

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

Questo problema noto è tracciato su GitHub e viene risolto in una versione futura.

L'analizzatore Roslyn genera cicli foreach

L'analizzatore Roslyn di Durable Task potrebbe generare un ArgumentNullException quando il codice lambda dell'agente di orchestrazione si trova all'interno di un ciclo foreach. Questo comportamento è un problema noto che non influisce sul comportamento di runtime. Eseguire l'aggiornamento alla versione più recente del pacchetto dell'analizzatore per ottenere la correzione.

Java

Errore permesso negato di Gradle

In macOS o Linux l'esecuzione ./gradlew potrebbe non riuscire con un errore di autorizzazione negata. Correggere questo errore rendendo eseguibile il file:

chmod +x gradlew

OrchestratorBlockedException

OrchestratorBlockedException si verifica quando il codice dell'agente di orchestrazione esegue un'operazione di blocco che l'SDK rileva come potenzialmente non deterministica. Questa eccezione è una protezione per impedire che il codice di orchestrazione violi i vincoli del codice dell'orchestratore.

Cause comuni:

  • Chiamata di un'API esterna bloccante nel codice di orchestrazione.
  • Uso Thread.sleep() diretto anziché di ctx.createTimer().
  • Esecuzione di I/O di file o di rete nel codice dell'orchestratore.

Spostare tutte le operazioni di blocco o I/O nelle attività.

Python

La politica di ritentativo richiede max_retry_interval

Quando si configura un retry_policy in Python, omettendo il parametro max_retry_interval viene generato un errore che non indica chiaramente la causa. Specificare 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 delle eccezioni di WhenAllTask

Quando si usa when_all per eseguire più attività in parallelo, se una o più attività hanno esito negativo, il comportamento dell'eccezione potrebbe non corrispondere alle aspettative. Viene generata solo la prima eccezione e le eccezioni dell'attività rimanenti potrebbero andare perse. Controllare i risultati delle singole attività se sono necessarie informazioni complete sull'errore:

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

Ottenere supporto

Per domande e bug di segnalazione, aprire un problema nel repository GitHub per l'SDK pertinente. Quando si segnala un bug, includere:

  • ID dell'istanza di orchestrazione interessata
  • Intervallo di tempo in formato UTC che mostra il problema
  • Nome dell'applicazione e area di distribuzione (se pertinente)
  • Versione dell'SDK e piattaforma di hosting
  • Log o messaggi di errore pertinenti
SDK GitHub repository (Repository GitHub)
.NET microsoft/durabletask-dotnet
Java microsoft/durabletask-java
JavaScript microsoft/durabletask-js
Python microsoft/durabletask-python

Passaggi successivi