Gestire le eccezioni in Task paralleli
Tempo fa ho scritto un post su come eseguire Task in parallelo o in seriale. Questa volta invece parleremo di come gestire correttamente le eccezioni in Task paralleli.
Supponiamo di dover effettuare delle chiamate ad alcuni microservizi. Magari la nostra applicazione è un API Gateway e dobbiamo aggregare i dati.
Supponiamo che le chiamate siano indipendenti fra di loro e possano quindi essere eseguite in parallelo. Come lo sviluppiamo? Molto semplicemente possiamo usare Task.WaitAll() oppure, ancora meglio, Task.WhenAll(). Qualcosa del genere:
Task.WhenAll() restituisce un Task quindi possiamo usare il costrutto async/await evitando cosi’ di bloccare il thread corrente.
Perfetto, ora supponiamo peró che qualcuna delle chiamate fallisca e lanci un’eccezione. Come possiamo gestire gli errori evitando di perdere informazioni preziose? Un blocco try/catch è sicuramente un buon inizio:
Questo funziona bene finché abbiamo una sola eccezione. Se piú chiamate falliscono Task.WhenAll() ci rilancerá purtoppo soltanto la prima. Questa e’ una delle differenze principali rispetto a Task.WaitAll() : quest’ultimo infatti raggruppa tutte le eccezioni e le rilancia all’interno di una AggregateException .
Quindi cosa possiamo fare? Passare a Task.WaitAll()? No, c’e’ una soluzione migliore.
Il trucco praticamente sta nel non usare await direttamente su Task.WhenAll(), bensí salvarne il risultato in una variabile. All’interno del blocco try/catch possiamo poi accedere alla property task.Exception, che sará di tipo AggregateException. A questo punto poi possiamo fare quello che vogliamo accedendo alla collezione InnerExceptions:
Come al solito ho pubblicato su Github un piccolo repository. All’interno troverete una console application in dotNet Core con vari esempi su come gestire le eccezioni dei in parallelo.