Un'applicazione robusta deve essere disegnata in modo da tenere in considerazione che le risorse esterne a cui accediamo, siano esse database o servizi, possano temporaneamente fallire. Questo è soprattutto vero in uno scenario cloud, in cui la stessa natura disconnessa dell'ambiente può essere causa di questi fault.
Spesso si tratta di problemi che durano lo spazio di qualche millisecondo, per cui, prima di restituire un messaggio di errore all'utente, può valere la pena effettuare un nuovo tentativo. Piuttosto che scrivere a mano il codice necessario, possiamo sfruttare una libreria come Polly: si tratta di un package NuGet che mette a disposizione una serie di primitive per gestire questo tipo di necessità.
Immaginiamo allora di avere un'interfaccia IContentService che astragga una chiamata al database o a una generica risorsa esterna:
public interface IContentService { Task<string[]> LoadArticlesAsync(); }
Normalmente, il nostro codice sul controller sarebbe qualcosa di simile al seguente:
private IContentService _content; public async Task<IActionResult> Index() { var articles = await _content.LoadArticlesAsync(); return View(articles); }
Ovviamente, in questo modo, una singola eccezione sulla connessione, causerebbe un errore e quindi una risposta di StatusCode 500 restituita all'utente.
Cerchiamo di capire come possiamo rendere allora l'applicazione più robusta. Il concetto base di Polly è rappresentato dalla classe Policy, tramite la quale possiamo specificare il comportamento che desideriamo implementare. Nel nostro caso, vogliamo effettuare in automatico qualche Retry, prima di fallire definitivamente.
public async Task<IActionResult> Index() { var policy = Policy .Handle<Exception>() .RetryAsync(retryCount:3); var articles = await policy.ExecuteAsync( () => _content.LoadArticlesAsync()); return View(articles); }
La fluent interface di Polly rende tutto estremamente leggibile e chiaro: tramite il metodo Handle abbiamo specificato che vogliamo gestire ogni possibile eccezione, ma ovviamente è possibile isolarne alcune specifiche. Successivamente, con RetryAsync, abbiamo indicato che vogliamo riprovare al massimo per 3 volte. Esistono diversi overload di questo metodo, alcuni con un callback che viene invocato automaticamente a ogni retry, così che possiamo per esempio loggare comunque l'errore.
L'ultimo step è la chiamata a ExecuteAsync, alla quale abbiamo passato il metodo effettivamente da eseguire.
Il codice in allegato mostra il tutto in funzione, con un'implementazione fittizia di IContentService che restituisce una risposta con successo solo al terzo tentativo.
Questo è solo un utilizzo basilare di Polly, nei prossimi script daremo un'occhiata a ulteriori funzionalità, utilissime per rendere più robusta la nostra applicazione.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Persistere la ChatHistory di Semantic Kernel in ASP.NET Core Web API per GPT
Proteggere le risorse Azure con private link e private endpoints
Creare una libreria CSS universale: i bottoni
Estrarre dati randomici da una lista di oggetti in C#
Utilizzare QuickGrid di Blazor con Entity Framework
Gestire i dati con Azure Cosmos DB Data Explorer
Generare token per autenicarsi sulle API di GitHub
Popolare una classe a partire dal testo, con Semantic Kernel e ASP.NET Core Web API
Criptare la comunicazione con mTLS in Azure Container Apps
Visualizzare le change sul plan di Terraform tramite le GitHub Actions
Utilizzare Model as a Service su Microsoft Azure
Sfruttare i KeyedService in un'applicazione Blazor in .NET 8