Circuit Breaker para protección del sistema.
Implementa el patrón Circuit Breaker con tres estados:
:closed— Operación normal; las llamadas se ejecutan directamente.:open— Las llamadas se bloquean inmediatamente tras exceder el umbral de fallos consecutivos.:half_open— Estado de prueba tras el timeout de recuperación. Se permite una llamada para verificar si el sistema se ha recuperado.
Decisión atómica
La decisión de permitir o bloquear la ejecución se toma de forma atómica
dentro del GenServer (get_state_and_check), eliminando la race condition
entre leer el estado y ejecutar la función.
Cierre desde half_open
En estado :half_open se requieren max(1, threshold / 2) éxitos
consecutivos para cerrar el circuito, mitigando el riesgo de cierre
prematuro ante llamadas concurrentes.
Un fallo en :half_open resetea el contador de éxitos acumulados al
volver a :open, garantizando que el próximo intento de recuperación
parta desde cero.
Tiempo de timeout
Se usa System.monotonic_time/1 para calcular el intervalo desde el último
fallo, inmune a ajustes de reloj del sistema (NTP, cambios manuales, etc.).
Registro
Cada breaker se registra via Registry con nombre único bajo
Arrea.CircuitBreaker.Registry.
Summary
Functions
Ejecuta una función protegida por el circuit breaker.
Returns a specification to start this module under a supervisor.
Notifica un fallo de ejecución al circuit breaker.
Obtiene el estado actual del circuit breaker (:closed, :open, :half_open).
Inicia un circuit breaker con nombre único (requerido en opts).
Notifica una ejecución exitosa al circuit breaker.
Types
Functions
Ejecuta una función protegida por el circuit breaker.
- Si el circuito está cerrado o en half_open: ejecuta la función.
- Si el circuito está abierto y el timeout no ha expirado: retorna
{:error, :circuit_open}sin ejecutar nada. - Si el breaker no está registrado: ejecuta la función directamente (comportamiento equivalente a circuito cerrado).
Ejemplos
iex> CircuitBreaker.call(:my_breaker, fn -> :ok end)
{:ok, :ok}
iex> CircuitBreaker.call(:my_breaker, fn -> raise "boom" end)
{:error, :execution_failed}
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec failure(atom()) :: :ok
Notifica un fallo de ejecución al circuit breaker.
Obtiene el estado actual del circuit breaker (:closed, :open, :half_open).
Retorna :closed si el breaker no está registrado.
@spec start_link(keyword()) :: GenServer.on_start()
Inicia un circuit breaker con nombre único (requerido en opts).
Opciones
:name— Nombre único del breaker (requerido):id— Alias de:nameaceptado por conveniencia:threshold— Número de fallos consecutivos para abrir el circuito (default: 5):timeout— Tiempo en ms antes de pasar a:half_open(default: 60_000)
@spec success(atom()) :: :ok
Notifica una ejecución exitosa al circuit breaker.