0Pricing
C# Academy · Lezione

Fondamenti di resilienza: retry e backoff

Implementate semplici retry con backoff esponenziale e jitter; distinguete gli errori transitori da quelli fatali, limitate i ritardi e interrompete l’operazione in caso di annullamento.

Fondamenti di resilienza: retry e backoff è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 3 lezioni in totale.

Perché usare retry e backoff

Obiettivo: renda resilienti le chiamate.

  • Riprovare in caso di errori transitori
  • Usare un backoff esponenziale con jitter
  • Impostare un numero massimo di tentativi e un ritardo massimo
  • Interrompere il processo in caso di errori fatali o annullamento

Classificazione degli errori

Transitori: timeout, errori 429/5xx, problemi temporanei di rete.

Fatali: richieste non valide, errori di autorizzazione, errori di convalida: non riprovi.

Regola: riprovi solo le operazioni che possono riuscire in seguito.

Helper per il backoff

Un piccolo helper aumenta il ritardo a ogni tentativo e aggiunge un piccolo jitter; limiti anche il ritardo massimo.

using System;
using System.Threading;
using System.Threading.Tasks;

public static class Backoff
{
  // Compute delay = min(base * 2^attempt, cap) + jitter
  public static int ComputeDelayMs(int attempt, int baseMs, int capMs, int jitterMs, Random rng)
  {
    long exp = (long)baseMs << attempt; // base * 2^attempt
    if (exp > capMs) exp = capMs;
    int jitter = rng.Next(0, jitterMs + 1); // [0..jitterMs]
    return (int)exp + jitter;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    Random rng = new Random(123);
    for (int i = 0; i < 5; i++)
    {
      int d = Backoff.ComputeDelayMs(i, 100, 2000, 50, rng);
      Console.WriteLine("Attempt " + i + " -> " + d + " ms");
    }
  }
}

Wrapper per i retry

Avvolga la chiamata: riprovi solo in caso di eccezioni transitorie; negli altri casi si fermi. Ogni nuovo tentativo attende più a lungo, con jitter.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
  static readonly Random Rng = new Random();

  // Simulate an operation that sometimes fails transiently.
  static async Task<string> FlakyAsync()
  {
    await Task.Delay(60);
    // 50% chance of transient failure
    if (DateTime.UtcNow.Ticks % 2 == 0) throw new TimeoutException("Transient");
    return "OK";
  }

  static async Task<T> RetryAsync<T>(Func<Task<T>> action, int maxAttempts)
  {
    int baseMs = 100, capMs = 2000, jitterMs = 50;
    for (int attempt = 0; attempt < maxAttempts; attempt++)
    {
      try
      {
        return await action();
      }
      catch (TimeoutException)
      {
        if (attempt == maxAttempts - 1) throw; // out of retries
        int delay = Backoff.ComputeDelayMs(attempt, baseMs, capMs, jitterMs, Rng);
        await Task.Delay(delay);
      }
      catch (Exception)
      {
        // Non-transient (unknown) -> do not retry
        throw;
      }
    }
    throw new InvalidOperationException("Unreachable");
  }

  public static void Main(string[] args)
  {
    try
    {
      string s = RetryAsync(FlakyAsync, 5).GetAwaiter().GetResult();
      Console.WriteLine("Result: " + s);
    }
    catch (Exception ex)
    {
      Console.WriteLine("Failed: " + ex.GetType().Name);
    }
  }
}

Retry con budget

Aggiunga un budget globale tramite l'annullamento: passi i token sia all'operazione sia ai ritardi del backoff.

using System;
using System.Threading;
using System.Threading.Tasks;

public static class RetryUtil
{
  static readonly Random Rng = new Random();

  public static async Task<T> RetryAsync<T>(Func<CancellationToken, Task<T>> action, int maxAttempts, CancellationToken ct)
  {
    int baseMs = 100, capMs = 1500, jitterMs = 50;
    for (int attempt = 0; attempt < maxAttempts; attempt++)
    {
      ct.ThrowIfCancellationRequested();
      try
      {
        return await action(ct);
      }
      catch (TimeoutException)
      {
        if (attempt == maxAttempts - 1) throw;
        int delay = Backoff.ComputeDelayMs(attempt, baseMs, capMs, jitterMs, Rng);
        await Task.Delay(delay, ct); // pass token so we can abort waiting
      }
    }
    throw new InvalidOperationException("Unreachable");
  }
}

public class Program
{
  static async Task<string> SometimesSlowAsync(CancellationToken ct)
  {
    await Task.Delay(200, ct);
    if (DateTime.UtcNow.Millisecond % 3 != 0) throw new TimeoutException("Transient");
    return "OK";
  }

  public static void Main(string[] args)
  {
    var cts = new CancellationTokenSource();
    cts.CancelAfter(800); // overall budget

    try
    {
      string s = RetryUtil.RetryAsync(SometimesSlowAsync, 5, cts.Token).GetAwaiter().GetResult();
      Console.WriteLine("Done: " + s);
    }
    catch (OperationCanceledException) { Console.WriteLine("Canceled"); }
    catch (Exception ex) { Console.WriteLine("Failed: " + ex.Message); }
  }
}

Linee guida

Suggerimenti:

  • Riprovi solo le chiamate idempotenti.
  • Imposti limiti sul numero di tentativi e sul ritardo.
  • Aggiunga un piccolo jitter per evitare picchi di richieste simultanee.
  • Registri il fallimento finale indicando il motivo e il numero di tentativi.

Definizione del backoff

Verifica rapida: quale descrizione illustra meglio il backoff esponenziale con jitter?

Riepilogo

Riepilogo: riprovi solo gli errori transitori, aumenti esponenzialmente i ritardi applicando un limite, aggiunga jitter e interrompa il processo in caso di annullamento o errori fatali.

Domande Frequenti

La lezione «Fondamenti di resilienza: retry e backoff» è gratuita?

Sì — il testo completo di «Fondamenti di resilienza: retry e backoff» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 3 lezioni in totale.

Cosa imparerò in «Fondamenti di resilienza: retry e backoff»?

Implementate semplici retry con backoff esponenziale e jitter; distinguete gli errori transitori da quelli fatali, limitate i ritardi e interrompete l’operazione in caso di annullamento. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.

Quanto tempo richiede la lezione «Fondamenti di resilienza: retry e backoff»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Pattern CancellationToken; annullamento cooperativo
  2. Timeout, IProgress , disposable asincroni (emulazione)
  3. Fondamenti di resilienza: retry e backoff
← Torna a C# Academy