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.