Il punto focale di una comunicazione gRPC è la creazione di un canale di comunicazione, il GrpcChannel. Attraverso questo canale passeranno tutte le richieste che il client invierà al server, e di conseguenza le risposte inoltrate dal server verso il chiamante.
Il GrpcChannel non è però un oggetto perfetto, tutt'altro: contrariamente a quanto avviene in una comunicazione WebAPI, in cui il ciclo di vita inizia nel momento della chiamata e termina alla ricezione della risposta, il canale di comunicazione gRPC può essere mantenuto attivo per più chiamate, e deve supportare una comunicazione basata sullo stream di dati, nella quale il server, o il client, inviano periodicamente nuovi dati all'interno della stessa chiamata.
Questa modalità di trasferimento di informazioni rende il GrpcChannel soggetto a errori temporanei, o Transient fault, che possono, anche per pochi istanti, interrompere la comunicazione con il server, andando ad invalidare tutte le chiamate in corso. Errori dovuti principalmente a perdita di connessione, indisponibilità del servizio o server timeout.
Fino ad ASP.NET Core 5 l'unico meccanismo di protezione verso questo tipo di errori, era l'implementazione di una logica basata sulla gestione di un'eccezione di tipo RpcException, come mostrato nel seguente codice:
var client = new Greeter.GreeterClient(channel); try { var response = await client.SayHelloAsync( new HelloRequest { Name = "Morgan" }); Console.WriteLine(response.Message); } catch (RpcException ex) { // Logica di retry }
Questo metodo richiedeva però la duplicazione di molto codice all'interno dell'applicazione: ovunque si fosse instaurato un canale di comunicazione avremmo dovuto gestire l'errore.
In ASP.NET Core 6 il canale supporta una logica di retry automatica basata su una configurazione, iniettata nel momento della creazione del canale.
var defaultMethodConfig = new MethodConfig { Names = { MethodName.Default }, RetryPolicy = new RetryPolicy { MaxAttempts = 5, InitialBackoff = TimeSpan.FromSeconds(1), MaxBackoff = TimeSpan.FromSeconds(5), BackoffMultiplier = 1.5, RetryableStatusCodes = { StatusCode.Unavailable } } }; var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } } });
La configurazione permette il settaggio di vari parametri:
- MaxAttemps: numero massimo di tentativi di retry
- InitialBackoff: tempo di attesa per il primo retry
- BackoffMultiplier: moltiplicatore del tempo di attesa dopo il primo retry
- MaxBackoff: tempo massimo di attesa prima di retry, mette un limite al valore che il moltiplicatore può generare
- RetryableStatusCodes: occasione nella quale eseguire la logica di retry
Il codice mostrato all'inizio non necessiterà più del blocco try/catch, venendo così riscritto:
var client = new Greeter.GreeterClient(channel); var response = await client.SayHelloAsync( new HelloRequest { Name = "Morgan" }); Console.WriteLine(response.Message);
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Utilizzare Azure Cosmos DB con i vettori
Migliorare l'organizzazione delle risorse con Azure Policy
Potenziare la ricerca su Cosmos DB con Full Text Search
Configurare il nome della run di un workflow di GitHub in base al contesto di esecuzione
Utilizzare il metodo ExceptBy per eseguire operazione di sottrazione tra liste
Utilizzare il metodo CountBy di LINQ per semplificare raggruppamenti e i conteggi
Supportare lo HierarchyID di Sql Server in Entity Framework 8
Filtering sulle colonne in una QuickGrid di Blazor
Garantire la provenienza e l'integrità degli artefatti prodotti su GitHub
Generare velocemente pagine CRUD in Blazor con QuickGrid
Gestione dei nomi con le regole @layer in CSS
Configurare lo startup di applicazioni server e client con .NET Aspire