Son las tres de la mañana y tu teléfono vibra. El servicio de pagos está devolviendo timeouts en cadena, la latencia se disparó hace doce minutos y alguien en el equipo jura que "para eso está el circuit breaker". Revisas el dashboard. El breaker abrió, sí. Pero nadie sabe cuánto tráfico está cayendo al vacío ahora mismo, ni por qué se abrió con ese umbral en particular, ni cuándo va a intentar cerrar de nuevo. Si esta escena te suena conocida, ya sabes de qué va este artículo: no de qué es un circuit breaker, sino de todo lo que la explicación de manual nunca te cuenta.
La definición corta ya la sabes de memoria. Un circuit breaker corta las llamadas hacia un servicio que está fallando para evitar que ese fallo se propague al resto del sistema. Bien. Es correcta y es completamente insuficiente. Porque implementar un circuit breaker en quince minutos con una librería es trivial. Hacer que ese circuit breaker tome buenas decisiones en producción, bajo carga real, con datos reales, es un problema de ingeniería serio que la mayoría de los equipos resuelve a medias y después olvida revisar.
Lo que el patrón circuit breaker realmente resuelve, y lo que no
El circuit breaker resuelve un problema concreto: evita que un servicio lento o caído consuma todos los threads, conexiones o recursos de quien lo llama, y evita que ese agotamiento se propague hacia arriba en la cadena de dependencias. Eso es real y es valioso. Cualquiera que haya visto un timeout de base de datos tumbar un API gateway entero entiende por qué existe este patrón.
Lo que no resuelve es la pregunta de qué hacer después. Un circuit breaker no arregla el servicio caído, no decide qué mostrarle al usuario, no te dice si el fallo es transitorio o estructural, y no reemplaza una estrategia de degradación. Es una válvula, no una solución. Y como toda válvula, su valor depende enteramente de cómo la calibras. Ahí es donde la mayoría de las implementaciones de circuit breaker se quedan cortas: se instalan como si fueran un checkbox de buenas prácticas y después nadie vuelve a tocarlas.
Calibrar los umbrales de fallo es la parte que nadie te explica bien
Todo tutorial te va a mostrar el mismo ejemplo: si el porcentaje de errores supera el 50% en una ventana de 10 segundos, abre el circuito. Se ve limpio en un diagrama. En producción es una pesadilla de decisiones que nadie documenta.
¿Ese 50% se mide sobre 10 requests o sobre 10.000? Porque con tráfico bajo, un puñado de errores dispara el breaker por pura casualidad estadística, y ahora estás cortando un servicio que en realidad está sano. ¿La ventana de tiempo es fija o deslizante? ¿Cuentas los timeouts igual que los errores 500, o un timeout de 30 segundos pesa distinto que un rechazo instantáneo? ¿El umbral es el mismo un martes a las 3 de la tarde con tráfico normal que un Black Friday con diez veces el volumen habitual?
La respuesta correcta casi nunca es un número fijo copiado de la documentación de tu librería favorita. Es un número que sale de mirar la distribución real de latencia y error de ese servicio específico, en esas condiciones específicas, y que se revisa cada vez que el patrón de tráfico cambia. Un circuit breaker calibrado en el lanzamiento de un servicio y nunca más tocado es, en el mejor de los casos, un placebo. En el peor, empieza a abrir por ruido y termina generando la misma inestabilidad que se supone que debía prevenir.
El estado half-open es donde vive toda la ambigüedad
De los tres estados del circuit breaker (cerrado, abierto, half-open), los dos primeros son fáciles de entender. El tercero es donde se define si tu implementación es seria o es de juguete.
El half-open existe para responder una pregunta incómoda: ¿ya se recuperó el servicio que falló? La forma naive de responderla es dejar pasar una request de prueba y, si funciona, cerrar el circuito de nuevo. El problema es que una sola request exitosa no dice nada sobre si el servicio soporta el volumen real de tráfico que le vas a mandar en cuanto cierres. Es común ver breakers que cierran, reciben la carga completa de golpe, el servicio recién recuperado se cae otra vez por el pico, y el circuit breaker vuelve a abrir. Ese ciclo se puede repetir indefinidamente y nadie lo nota como un problema del breaker, lo leen como que "el servicio downstream sigue mal".
Las implementaciones que funcionan de verdad usan el half-open para dejar pasar tráfico de forma gradual, no binaria: un porcentaje pequeño primero, y si se sostiene sano durante un período razonable, se va aumentando. También conviene decidir explícitamente cuánto tiempo espera el breaker antes de intentar el half-open, y ese tiempo tampoco debería ser un número mágico copiado de un ejemplo. Si es muy corto, generas el ciclo de apertura y cierre constante. Si es muy largo, mantienes un servicio saludable innecesariamente aislado mientras el resto del sistema opera en modo degradado sin necesidad.
Qué pasa con las requests que caen cuando el circuit breaker está abierto
Esta es la pregunta que casi ningún equipo responde antes de que pase en producción por primera vez. El circuit breaker abrió. Genial, evitó que el fallo se propagara. ¿Y ahora qué le devuelves al que hizo la llamada?
Las opciones reales son pocas y todas tienen costo. Puedes fallar rápido y devolver un error explícito, lo cual es honesto pero empuja el problema hacia arriba en la cadena: ahora el servicio que te llamó a ti tiene que decidir qué hacer con ese error. Puedes devolver una respuesta cacheada o un valor por defecto, lo cual funciona bien para catálogos de producto o recomendaciones, y es directamente peligroso para cualquier cosa que tenga que ver con inventario, saldo o autorización de pagos. Puedes encolar la request para reintentar después, lo cual solo tiene sentido si la operación tolera ser asíncrona y el usuario no está esperando una respuesta inmediata en pantalla.
No existe una respuesta universal, y eso es exactamente el punto: cada dependencia que envuelves en un circuit breaker necesita una decisión explícita y documentada sobre su estrategia de fallback, tomada por alguien que entiende el negocio detrás de esa llamada. Copiar la misma estrategia de fallback para diez servicios distintos porque "así viene en el ejemplo del framework" es la forma más común de convertir un circuit breaker en una fuente de bugs silenciosos.
Un circuit breaker sin observabilidad es peor que no tener ninguno
Acá está la parte incómoda de este artículo. Un circuit breaker que abre y cierra sin que nadie lo vea, sin métricas de cuántas veces cambió de estado, sin alertas cuando pasa más tiempo abierto de lo esperado, sin visibilidad de cuánto tráfico está cayendo mientras está abierto, no te está protegiendo. Te está mintiendo.
El equipo que lo instaló duerme tranquilo pensando que "ya tenemos resiliencia cubierta". Mientras tanto, el breaker puede estar abriendo cinco veces por hora por un umbral mal calibrado, descartando silenciosamente un porcentaje real de tráfico de usuarios, sin que nadie lo note hasta que alguien de soporte pregunta por qué las conversiones bajaron un 8% la semana pasada. Un sistema sin circuit breaker al menos falla de forma visible: el error llega, alguien lo ve, alguien reacciona. Un circuit breaker mal observado convierte ese fallo visible en un fallo silencioso, y eso, en cualquier sistema en producción, es estrictamente peor.
Lo mínimo no negociable es exponer el estado actual de cada breaker como métrica, contar transiciones de estado, medir el volumen de requests rechazadas mientras está abierto, y tener una alerta que dispare cuando un breaker pasa más tiempo del esperado sin cerrar. Sin eso, el circuit breaker deja de ser una herramienta de resiliencia y se convierte en un punto único de falla adicional: uno que además es invisible, porque nadie lo está mirando.
La conclusión que importa
Un circuit breaker bien calibrado, con un half-open diseñado con cuidado, con estrategias de fallback pensadas por dependencia y con observabilidad real, es una de las piezas más valiosas que puedes tener en un sistema distribuido. Pero esa combinación es rara. Lo habitual es una librería instalada con la configuración por defecto, un umbral que nadie volvió a mirar desde el día del despliegue, y cero alertas si algo sale mal.
Mi posición es simple y no es la que vas a leer en la documentación de la librería: un circuit breaker sin métricas y sin alertas reales es, en la práctica, peor que no tener ninguno. Sin observabilidad, un circuit breaker no te da resiliencia, te da la ilusión de resiliencia, que es mucho más peligrosa porque te hace bajar la guardia exactamente en el lugar donde más la necesitas. Si vas a poner uno en producción, la pregunta que define si vale la pena no es "¿qué librería uso?". Es "¿quién se entera, y qué tan rápido, cuando este breaker empieza a comportarse mal?". Si no tienes una respuesta clara a eso, todavía no tienes un circuit breaker. Tienes una promesa de uno.



