Circuit Breaker
Qué es
Circuit Breaker es un patrón de admisión que interrumpe temporalmente llamadas a una dependencia cuando sus resultados indican que continuar probablemente desperdiciará recursos o agravará un fallo. Utiliza observaciones recientes y una política de recuperación para decidir cuándo permitir tráfico otra vez.
No repara la dependencia. Tampoco equivale a retry: Retry decide repetir una intención; el breaker decide si admite una llamada. No es un health check: una prueba de salud puede aportar evidencia, pero no constituye por sí sola la política de admisión ni demuestra que una operación real funcionará.
Qué problema resuelve
Cuando una dependencia falla de manera persistente, cada llamada puede retener conexiones, memoria y tiempo hasta su timeout. Continuar enviando solicitudes consume recursos del caller y carga el componente que intenta recuperarse. Los reintentos pueden amplificar ese tráfico.
El breaker cambia esa espera costosa por un rechazo local temporal. El caller recibe una señal de indisponibilidad y puede terminar la operación o seguir una alternativa expresamente definida por su contrato. El patrón no introduce automáticamente una respuesta de respaldo ni convierte datos incompletos en éxito.
Estados y recuperación
El patrón descrito por Azure Architecture Center distingue tres estados habituales: Closed permite llamadas y observa resultados; Open rechaza llamadas; Half-Open admite pruebas limitadas para evaluar recuperación.
Closed
-> suficientes fallos relevantes -> Open
-> periodo de apertura cumplido -> Half-Open / probes
-> evidencia de recuperación -> Closed
-> evidencia de fallo persistente -> OpenEl diagrama describe un ciclo, no una implementación obligatoria. La transición a prueba puede ocurrir al vencer un temporizador o cuando llega una llamada posterior. La cantidad de probes, los umbrales y la evidencia requerida para cerrar pertenecen a la política concreta.
Abrir el circuito no cancela automáticamente llamadas ya admitidas. Sus resultados pueden llegar después y deben tratarse de manera coherente con el estado actual. Un rechazo local tampoco prueba que un intento anterior de la misma intención no haya producido efectos remotos.
Clasificación y ventanas
Primero se define qué cuenta como fallo relevante. Problemas de conexión, indisponibilidad y ciertas respuestas del servidor pueden indicar una dependencia deteriorada. Una solicitud inválida o una reserva rechazada por falta de stock pueden ser resultados correctos del dominio; contarlos indiscriminadamente produciría aperturas falsas.
Una llamada lenta también puede ser relevante aunque termine con éxito, pero requiere una definición de lentitud compatible con su contexto. Un Timeout demasiado pequeño puede hacer que el breaker interprete como caída un servicio que responde dentro de su latencia habitual.
La evaluación puede utilizar una ventana de llamadas o una ventana temporal, tasas de fallo, fallos consecutivos y una cantidad mínima de muestras. Una política ilustrativa podría exigir veinte observaciones antes de evaluar un umbral del 50 %. No es una recomendación general: el volumen, la variabilidad y el costo de rechazar tráfico determinan la configuración.
La documentación de Resilience4j muestra ventanas por cantidad o tiempo, un mínimo de llamadas y umbrales de fallos o lentitud. Son opciones de una biblioteca concreta; la semántica del patrón no exige exactamente esos mecanismos.
Duración de apertura y probes
Una apertura corta permite comprobar recuperación pronto, pero puede generar oscilaciones y tráfico sobre una dependencia todavía saturada. Una larga evita insistir, a costa de rechazar trabajo después de que el servicio ya se recuperó.
Los probes deben ser limitados y tener sus propios Timeout y deadline. Permitir todo el tráfico al vencer el periodo de apertura convierte la comprobación en otra oleada. jitter puede dispersar pruebas entre instancias, sin reemplazar el límite de admisión.
La evidencia debe representar las operaciones protegidas. Que una ruta de health check responda no demuestra que una escritura, una partición o una credencial específica funcionen. Los éxitos necesarios para cerrar y la reacción ante un fallo durante la prueba deben quedar definidos.
Ejemplo: servicio de reservas
Un servicio de pedidos llama a inventario para reservar unidades. Una caída de inventario produce fallos de conexión repetidos. Tras reunir evidencia suficiente, el breaker abre y nuevas llamadas se rechazan localmente. Luego admite unas pocas reservas de prueba; según sus resultados, vuelve a permitir tráfico o mantiene la interrupción.
Una reserva anterior pudo completarse aunque su respuesta no llegara. La reapertura no habilita crear otra reserva como si la primera nunca hubiera ocurrido. La identidad de la intención y idempotency siguen siendo necesarias para reintentar de manera segura.
Si inventario está saludable y responde «sin stock», ese resultado no debería abrir el circuito por confundirse con un fallo de infraestructura. Si solamente falla una partición, un breaker global puede impedir operaciones contra particiones sanas.
Estado local o compartido
Un breaker local observa la experiencia de un proceso. Es simple y no requiere coordinación adicional, pero otras instancias pueden mantener estados distintos o probar recuperación simultáneamente. Esa divergencia no es necesariamente un error: pueden usar rutas diferentes.
Compartir estado puede coordinar admisión entre procesos, pero añade dependencia, latencia y decisiones ante la pérdida del mecanismo de coordinación. También amplía el impacto de una clasificación equivocada. El alcance debe explicitar qué dependencia, operación o grupo de destinos protege, sin asumir que toda la plataforma comparte una única salud.
El tamaño de una ventana tampoco limita concurrencia. Resilience4j lo aclara expresamente: el registro de resultados no constituye un límite de llamadas simultáneas. Un circuito cerrado puede admitir más trabajo del que el caller soporta.
Interacción con Retry y límites
Cada intento real debe respetar la política de admisión correspondiente. Reintentar inmediatamente un rechazo de circuito abierto no contacta la dependencia ni aporta evidencia nueva. Consume presupuesto local y puede ocultar la señal de indisponibilidad.
La posición del breaker respecto de una política de Retry afecta sus observaciones: puede ver cada intento fallido o solamente el resultado final de una operación que hizo varios intentos internos. Esa elección modifica tiempos de apertura y visibilidad de carga; debe ser deliberada.
Es útil ante fallos persistentes de dependencias donde rechazar temporalmente es preferible a insistir. No corrige validaciones, efectos duplicados o capacidad insuficiente en condiciones normales. Hay que observar llamadas admitidas, rechazos, causas, transiciones y resultados de probes, y conservar una vía de diagnóstico cuando la apertura reduce el tráfico visible. resilience-patterns conecta esta decisión con las de espera, repetición y espaciamiento.