circuit_breaker
Circuit breaker for Gleam — closed, open, half-open states with OTP actor support.
Installation
gleam add circuit_breaker
Usage
Pure state machine
For applications that manage their own state, use circuit_breaker directly:
import circuit_breaker
let config = circuit_breaker.CircuitConfig(
failure_threshold: 5,
recovery_timeout_ms: 30_000,
half_open_max_calls: 2,
)
let cb = circuit_breaker.new("my_service", config)
let cb = case circuit_breaker.is_call_allowed(cb, config) {
circuit_breaker.Allow(cb) ->
case call_my_service() {
Ok(_) -> circuit_breaker.record_success(cb, config)
Error(_) -> circuit_breaker.record_failure(cb, config)
}
circuit_breaker.Block(cb) -> cb
}
OTP actor (thread-safe, multi-key)
For concurrent applications, use the actor — one instance manages multiple independent keys:
import circuit_breaker
import circuit_breaker/actor
let config = circuit_breaker.CircuitConfig(
failure_threshold: 5,
recovery_timeout_ms: 30_000,
half_open_max_calls: 2,
)
let assert Ok(cb) = actor.start(config)
case actor.check_and_call(cb, "my_service") {
actor.Allowed ->
case call_my_service() {
Ok(_) -> actor.record_success(cb, "my_service")
Error(_) -> actor.record_failure(cb, "my_service")
}
actor.Blocked(_) -> Nil
}
Global registry
When you can’t pass the actor subject through the call stack:
import circuit_breaker/actor
import circuit_breaker/global
// At application startup:
let assert Ok(cb) = actor.start(config)
global.set(cb)
// From anywhere:
case global.check_and_call("my_service") {
actor.Allowed -> // proceed
actor.Blocked(_) -> // fail fast
}
State transitions
Closed ──[failures ≥ threshold]──► Open
▲ │
│ [timeout]
│ ▼
└──[successes ≥ max_calls]──── HalfOpen ──[any failure]──► Open
| State | Behaviour |
|---|---|
| Closed | Normal operation; all calls pass through |
| Open | Circuit tripped; calls rejected immediately (fail fast) |
| HalfOpen | Recovery probe; limited calls allowed to test the downstream |