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
Configurare lo startup di applicazioni server e client con .NET Aspire
La gestione della riconnessione al server di Blazor in .NET 9
Collegare applicazioni server e client con .NET Aspire
Utilizzare una qualunque lista per i parametri di tipo params in C#
Usare il colore CSS per migliorare lo stile della pagina
Recuperare l'ultima versione di una release di GitHub
Eseguire query in contemporanea con EF
Gestire il colore CSS con HWB
Autenticazione di git tramite Microsoft Entra ID in Azure DevOps
Utilizzare l'espressione if inline in una pipeline di Azure DevOps
Rendere le variabili read-only in una pipeline di Azure DevOps
Generare HTML a runtime a partire da un componente Razor in ASP.NET Core