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

Composable resilience middleware for Elixir.

Provides bulkhead, circuit breaker, retry, and rate limiter patterns
as independently usable GenServer-based layers that compose into
an ordered pipeline.

## Standalone Usage

Each pattern can be used on its own:

    {:ok, _} = ExResilience.Bulkhead.start_link(name: :http_pool, max_concurrent: 10)
    {:ok, response} = ExResilience.Bulkhead.call(:http_pool, fn -> HTTPClient.get(url) end)

## Pipeline Usage

    pipeline =
      ExResilience.new(:my_service)
      |> ExResilience.add(:bulkhead, max_concurrent: 10)
      |> ExResilience.add(:circuit_breaker, failure_threshold: 5)
      |> ExResilience.add(:retry, max_attempts: 3)

    {:ok, _pids} = ExResilience.start(pipeline)
    result = ExResilience.call(pipeline, fn -> HTTPClient.get(url) end)

Layers execute in the order added (outermost first). The example above
runs: Bulkhead -> Circuit Breaker -> Retry -> function.

# `add`

```elixir
@spec add(ExResilience.Pipeline.t(), atom(), keyword()) :: ExResilience.Pipeline.t()
```

Adds a layer to the pipeline.

See `ExResilience.Pipeline.add/3` for supported layers and options.

## Examples

    iex> pipeline = ExResilience.new(:svc) |> ExResilience.add(:retry, max_attempts: 2)
    iex> length(pipeline.layers)
    1

# `call`

```elixir
@spec call(ExResilience.Pipeline.t(), (-&gt; term())) :: term()
```

Executes `fun` through the pipeline layers.

Layers must be started first via `start/1`.

# `new`

```elixir
@spec new(atom()) :: ExResilience.Pipeline.t()
```

Creates a new pipeline with the given name.

The name is used as a prefix for child process names and in
telemetry metadata.

## Examples

    iex> pipeline = ExResilience.new(:my_service)
    iex> pipeline.name
    :my_service

# `start`

```elixir
@spec start(ExResilience.Pipeline.t()) :: {:ok, [pid()]}
```

Starts all GenServer-backed layers in the pipeline.

Returns `{:ok, pids}`.

# `start_link`

```elixir
@spec start_link(
  ExResilience.Pipeline.t(),
  keyword()
) :: Supervisor.on_start()
```

Starts a pipeline supervisor for the given pipeline.

This is the preferred way to run a pipeline in a supervision tree.
For standalone or test usage, see `start/1`.

## Examples

    pipeline =
      ExResilience.new(:my_service)
      |> ExResilience.add(:bulkhead, max_concurrent: 10)
      |> ExResilience.add(:circuit_breaker, failure_threshold: 5)

    {:ok, sup} = ExResilience.start_link(pipeline)

---

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