# `ExResilience.CircuitBreaker`
[🔗](https://github.com/joshrotenberg/ex_resilience/blob/v0.4.0/lib/ex_resilience/circuit_breaker.ex#L1)

Circuit breaker implemented as a GenServer.

Tracks consecutive failures and transitions through three states:

  * `:closed` -- calls pass through. Failures increment the counter.
  * `:open` -- calls are rejected immediately with `{:error, :circuit_open}`.
    After `reset_timeout` ms, transitions to `:half_open`.
  * `:half_open` -- allows trial calls. After `success_threshold` consecutive
    successes the breaker resets to `:closed`; any failure reopens to `:open`.

## Options

  * `:name` -- required. Registered name for this breaker instance.
  * `:failure_threshold` -- consecutive failures before opening. Default `5`.
  * `:reset_timeout` -- ms to wait in `:open` before trying `:half_open`. Default `30_000`.
  * `:half_open_max_calls` -- concurrent calls allowed in `:half_open`. Default `1`.
  * `:success_threshold` -- consecutive successes required in `:half_open` before
    transitioning back to `:closed`. Default `1` (immediate close on first success).
  * `:error_classifier` -- controls which results count as failures.
    Accepts either a module implementing `ExResilience.ErrorClassifier`
    (classifications `:retriable` and `:failure` count as failures) or a
    1-arity function returning `true` for failures (backward compatible).
    Default: matches `{:error, _}` and `:error`.

## Examples

    iex> {:ok, _} = ExResilience.CircuitBreaker.start_link(name: :test_cb, failure_threshold: 2, reset_timeout: 100)
    iex> ExResilience.CircuitBreaker.call(:test_cb, fn -> :ok end)
    {:ok, :ok}

# `option`

```elixir
@type option() ::
  {:name, atom()}
  | {:failure_threshold, pos_integer()}
  | {:reset_timeout, pos_integer()}
  | {:half_open_max_calls, pos_integer()}
  | {:success_threshold, pos_integer()}
  | {:error_classifier, module() | (term() -&gt; boolean())}
```

# `result`

```elixir
@type result() :: {:ok, term()} | {:error, :circuit_open} | {:error, term()}
```

# `state_name`

```elixir
@type state_name() :: :closed | :open | :half_open
```

# `call`

```elixir
@spec call(atom(), (-&gt; term())) :: result()
```

Executes `fun` through the circuit breaker.

Returns `{:ok, result}` on success, `{:error, :circuit_open}` if the
breaker is open, or `{:error, reason}` if the function returns an error.

Raises if the function raises (the raise counts as a failure).

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `get_info`

```elixir
@spec get_info(atom()) :: %{
  state: state_name(),
  failure_count: non_neg_integer(),
  success_count: non_neg_integer()
}
```

Returns detailed information about the circuit breaker state.

# `get_state`

```elixir
@spec get_state(atom()) :: state_name()
```

Returns the current state of the circuit breaker.

# `reset`

```elixir
@spec reset(atom()) :: :ok
```

Manually resets the circuit breaker to `:closed`.

# `start_link`

```elixir
@spec start_link([option()]) :: GenServer.on_start()
```

Starts a circuit breaker process.

See module docs for available options.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
