Saltar al contenido principal
12 min lectura Erick Escobar

Patrones de Resiliencia en Arquitecturas Modernas de .NET

La resiliencia no es solo implementar *retries*; requiere un diseño consciente que incorpore patrones de aislamiento, Circuit Breaker y *Bulkhead* desde la capa de infraestructura, como lo exige la arquitectura distribuida moderna.

#dotnet #tutorial #2026

\n# Patrones de Resiliencia en Arquitecturas Modernas de .NET\n\nLa resiliencia en una aplicación de .NET moderna no es un parche de try-catch; es una disciplina de diseño. Si solo reintentamos llamadas ciegamente, sobrecargamos un servicio ya caído, garantizando un colapso lento y controlado. El problema fundamental en sistemas distribuidos es que el fallo es un estado base (DDIA). La resiliencia es, por lo tanto, la gestión activa de esos fallos para que el sistema opere de la manera menos destructiva posible.

Más Allá de los Reintentos: Implementando Circuit Breaker en .NET

Los reintentos son útiles, pero insuficientes. Si un servicio externo está sobrecargado, reintentar solo lo agrava. El patrón Circuit Breaker actúa como un fusible, deteniendo proactivamente las solicitudes cuando un servicio muestra fallos recurrentes. Esto le da al servicio tiempo para recuperarse, en lugar de seguir siendo bombardeado.

Para implementarlo en .NET, usamos bibliotecas como Polly. Esto permite definir un umbral de error y un tiempo de pausa. Como Martín insiste en Clean Code, la intención de nuestro código debe ser inconfundible: el CircuitBreaker es esa declaración de protección arquitectónica.

// Ejemplo de implementación de Circuit Breaker con Polly
var policy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreaker(
        handledEventsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromSeconds(30));

try
{
    await policy.ExecuteAsync(() => httpClient.GetAsync("api/critical"));
}
catch (BrokenCircuitException)
{
    // En modo abierto, activamos un mecanismo de respuesta degradada.
    // Esto es crítico: no solo loggeamos, sino que devolvemos datos de fallback.
    Console.WriteLine("El servicio está temporalmente inaccesible. Devolviendo respuesta degradada.");
}

Aislar el Riesgo: El Principio Bulkhead para Servicios Críticos

El Circuit Breaker protege un punto, pero ¿qué sucede si múltiples fallos saturan un único thread pool compartido? Aquí es donde entra el Bulkhead (compartimento estanco). Este principio exige que cada componente crítico tenga su propio conjunto de recursos dedicados.

Al implementar Bulkheads, evitamos que la lentitud o el fallo de un subsistema (ej. notificaciones) consuma los recursos del sistema principal (ej. checkout). Esto minimiza el alcance del fallo (blast radius), aislando el problema y protegiendo el resto del sistema.

Modularidad y Dependencias: Inyectando Resiliencia con MediatR y Políticas

Para que la resiliencia sea inherente al diseño, debemos modularizarla. Utilizamos patrones como Mediator (ej. MediatR) para desacoplar el comando de su ejecutor. La política de resiliencia se inyecta en el punto de ejecución del handler, manteniendo el código de negocio enfocado. El diseño limpio exige responsabilidades singulares.

Observabilidad de la Resiliencia: Métricas clave para validar el diseño

Un diseño resiliente es un diseño medible. No es suficiente implementar el Circuit Breaker; debemos observar su comportamiento. Nuestro foco debe estar en las métricas de fallo (4xx, 5xx) y, crucialmente, en la frecuencia de activación de los fusibles. Nosotros monitoreamos la tasa de errores y la activación del Circuit Breaker para validar que la protección está operando según lo planeado.

Conclusión: La resiliencia en .NET es una disciplina arquitectónica. Requiere pasar de la mentalidad de “esperar que no falle” a la de “diseñar para el fallo”, utilizando patrones como el Bulkhead y el Circuit Breaker como herramientas de ingeniería activa.\n

¿Te gustó este artículo? Compártelo: