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.
Summary
Functions
Adds a layer to the pipeline.
Executes fun through the pipeline layers.
Creates a new pipeline with the given name.
Starts all GenServer-backed layers in the pipeline.
Starts a pipeline supervisor for the given pipeline.
Functions
@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
@spec call(ExResilience.Pipeline.t(), (-> term())) :: term()
Executes fun through the pipeline layers.
Layers must be started first via start/1.
@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
@spec start(ExResilience.Pipeline.t()) :: {:ok, [pid()]}
Starts all GenServer-backed layers in the pipeline.
Returns {:ok, pids}.
@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)