Ritentare query fallite con Microsoft.Data.SqlClient

Da qualche anno a questa parte abbiamo visto nascere la nuova libreria Microsoft.Data.SqlClient, inizialmente “uguale” alla famosissima System.Data.SqlClient, ma sulla quale verranno portati avanti tutti i futuri sviluppi.

E’ possibile aggiornare da System.Data.SqlClient a Microsoft.Data.SqlClient senza dover eseguire refactoring al codice!

Come implementare la logica di retry?

Come prima cosa dobbiamo installare il pacchetto nuget della nuova libreria (se hai installato System.Data.SqlClient disinstallala prima di procedere)

C#
dotnet add package Microsoft.Data.SqlClient

A questo punto siamo pronti per mettere mano al codice. Il primo passaggio è quello di andare a definire un oggetto che descriva come si dovrà comportare il SqlClient in caso di fault:

C#
var retryLogicOptions = new SqlRetryLogicOption
        {
            NumberOfTries = 5,
            DeltaTime = TimeSpan.FromSeconds(2),
            MaxTimeInterval = TimeSpan.FromSeconds(50),
            RetryLogicProvider = SqlRetryLogicOption.CreateExponentialRetryProvider(),
            TransientErrors = new List<int> { 4060, 10928, 10929 }
        };

Le proprietà sono:

NumberOfTriesQuante volte verrà ritentata la query
DeltaTimeIntervallo di tempo tra i tentativi, utilizzato in combinazione con la strategia di retry.
MaxTimeIntervalIntervallo massimo di tempo totale consentito per tutti i retry combinati. Aiuta a prevenire tentativi eccessivi.
RetryLogicProviderLa logica di retry da utilizzare. Può essere una logica predefinita (ad esempio esponenziale o intervallo fisso) o una personalizzata.
TransientErrorsUna collezione di codici errore SQL Server da trattare come transitori. Può essere personalizzata per gestire scenari specifici. Gli errori che sono inclusi in questa lista innescheranno la logica di retry, quelli non inseriti qui dentro invece genereranno un’exception. Definendo solamente gli errori che possono essere transitori (come una mancata connessione al database) evitiamo che il meccanismo di retry venga applicato anche ad errori che sono di altra natura (es. un errore nella query o nella store procedure)
RetryableMethodIndica quali metodi/operazioni SQL possono essere soggetti alla retry logic (Open, Execute, OpenAndExecute, None). Se scegliamo Open, per esempio, la retry policy gestirà solo gli errori che si verificano durante l’apertura della connessione.

A questo punto siamo pronti per eseguire la nostra query, specificando la retry policy che abbiamo appena configurato:

C#
using (var connection = new SqlConnection("ConnectionString"))
{
    //Qui specifichiamo la logica di retry
    connection.RetryLogicProvider = retryLogicOptions;

    try
    {
        connection.Open();
        using (var command = connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM JediMasters";
            
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    Console.WriteLine(reader[0]);
                }
            }
        }
    }
    catch (SqlException ex)
    {
        //Exception
    }
}

Quando verrà eseguito command.ExecuteReader() e l’esecuzione andrà in errore allora si attiveranno i successivi tentativi secondo questa logica:

Primo Tentativo: 2 secondi

Secondo Tentativo: 4 secondi

Terzo Tentativo: 8 secondi

Quarto Tentativo: 16 secondi

Quinto Tentativo: 32 secondi

Il totale sarà quindi 62 secondi. Nella property MaxTimeInterval abbiamo però impostato 50 secondi, questo significa che dopo questo tempo verrà generata l’exception!

Conclusioni

Abbiamo visto come rendere più resiliente il nostro codice con questa funzionalità “by design” nella nuova libreria Microsoft.Data.SqlClient, la quale ci mette a disposizione un metodo per poter gestire una serie di tentativi di ri-esecuzione delle query a fronte di determinati errori o determinati stati.

In passato mi è capitato più volte di dover gestire questa logica tramite la libreria Polly), altre volte ancora ho dovuto implementare una logica custom con dei cicli while, da oggi il mio primo pensiero sarà sicuramente quello di usare questa libreria, senza nessuna dipendenza esterna!

Se pensi che questa pillola ti sia stata utile condividila con qualche tuo collega!

Buona programmazione!

Condividi questo articolo
Shareable URL
Prosimo post

Alla scoperta di Span<T>

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Leggi il prossimo articolo