0Pricing
C# Academy · Lección

Fundamentos de resiliencia: reintentos y backoff

Implemente reintentos sencillos con backoff exponencial y jitter; distinga errores transitorios de errores fatales, limite las esperas y deténgase al cancelar.

Fundamentos de resiliencia: reintentos y backoff es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 3 lecciones en total.

Por qué usar reintentos y espera progresiva

Objetivo: Hacer que las llamadas sean resistentes.

  • Reintentar fallos transitorios
  • Usar una espera progresiva exponencial con variación aleatoria
  • Establecer un máximo de intentos y un retraso máximo
  • Detenerse ante errores fatales o cancelaciones

Clasificación de fallos

Transitorios: tiempos de espera agotados, respuestas 429/5xx y problemas temporales de red.

Fatales: solicitud incorrecta, falta de autorización y errores de validación; no se deben reintentar.

Regla: reintentar solo aquello que pueda tener éxito más adelante.

Ayudante para la espera progresiva

Un pequeño ayudante aumenta el retraso en cada intento y añade una pequeña variación aleatoria; también limita el retraso máximo.

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");
    }
  }
}

Envoltorio de reintentos

Envolver la llamada: reintentar únicamente ante excepciones transitorias y detenerse ante las demás. Cada reintento espera un poco más y añade una variación aleatoria.

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);
    }
  }
}

Reintentos con presupuesto

Añadir un presupuesto global mediante la cancelación: pasar tokens tanto a la operación como a los retrasos entre reintentos.

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); }
  }
}

Directrices

Consejos:

  • Reintentar únicamente las llamadas idempotentes.
  • Establecer límites para los intentos y el retraso.
  • Añadir una pequeña variación aleatoria para evitar el efecto estampida.
  • Registrar el fallo final con el motivo y el número de intentos.

Definición de espera progresiva

Comprobación rápida: ¿Qué describe mejor la espera progresiva exponencial con variación aleatoria?

Resumen

Resumen: Reintentar únicamente los errores transitorios, aumentar los retrasos de forma exponencial con un límite, añadir variación aleatoria y detenerse ante una cancelación o errores fatales.

Preguntas frecuentes

¿La lección «Fundamentos de resiliencia: reintentos y backoff» es gratis?

Sí — el texto completo de «Fundamentos de resiliencia: reintentos y backoff» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 3 lecciones en total.

¿Qué aprenderé en «Fundamentos de resiliencia: reintentos y backoff»?

Implemente reintentos sencillos con backoff exponencial y jitter; distinga errores transitorios de errores fatales, limite las esperas y deténgase al cancelar. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 3.

¿Cuánto tiempo toma la lección «Fundamentos de resiliencia: reintentos y backoff»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Patrones de CancellationToken y cancelación cooperativa
  2. Timeouts, IProgress y disposables async (emulación)
  3. Fundamentos de resiliencia: reintentos y backoff
← Volver a C# Academy