Lightweight ETS-backed circuit breaker for MCP tool/resource callbacks.
Tracks failure counts per key and transitions through three states:
- closed -- normal operation, failures below threshold
- open -- callback blocked after repeated failures, returns
{:error, :circuit_open} - half_open -- recovery probe allowed after cooldown; success resets, failure re-opens
No GenServer -- all state lives in a public ETS table with atomic counter
updates. The table is created by the owning process (typically MCP.Registry),
and it lives exactly as long as that process: a caller that creates its own
gets a breaker nobody else can see, which for a failover gate means failover
never trips.
Keys
A key names what is being guarded. {:tool, _}, {:resource, _} and
{:prompt, _} are MCP callbacks; {:origin, _} is an outbound upstream,
used by raxol_web3's guarded client so a challenge-serving or hard-down
explorer is not retried on every call. Nothing here is MCP-specific but the
module's home, which is why the type widened rather than a second breaker
being written.
Configuration
Defaults can be overridden via application env or per-call opts:
config :raxol_mcp, :circuit_breaker,
failure_threshold: 5,
recovery_ms: 30_000
Summary
Functions
Check the circuit state for a key.
The failure count that opens a circuit: opts[:failure_threshold], then
app config, then the default (5). What record_failure/3 applies.
Create a new circuit breaker ETS table.
Record a failed callback invocation.
Record a successful callback invocation. Resets the circuit to closed.
Manually reset a circuit to closed.
Reset all circuit breaker state.
Get the current status of a circuit.
Types
Functions
Check the circuit state for a key.
Returns :closed (proceed), :open (block), or :half_open (probe).
Automatically transitions from open to half_open after the recovery period.
@spec failure_threshold(keyword()) :: pos_integer()
The failure count that opens a circuit: opts[:failure_threshold], then
app config, then the default (5). What record_failure/3 applies.
Create a new circuit breaker ETS table.
Record a failed callback invocation.
Increments the failure counter. Transitions to open when the threshold is reached. In half_open state, a single failure re-opens the circuit.
Record a successful callback invocation. Resets the circuit to closed.
Manually reset a circuit to closed.
@spec reset_all(:ets.tid()) :: :ok
Reset all circuit breaker state.
@spec status(:ets.tid(), key()) :: %{state: state(), failures: non_neg_integer()}
Get the current status of a circuit.