SuperWorker.CircuitBreaker (SuperWorker v0.6.0)

Copy Markdown View Source

A simple Circuit Breaker implementation for protecting external API calls.

The circuit breaker has three states:

  • :closed - Normal operation, requests go through
  • :open - Requests are short-circuited (fail fast)
  • :half_open - Testing if the service has recovered

The protected function is executed in the caller process, so slow calls never block the breaker process itself and concurrent calls are not serialized through a single process.

Usage

# Protect an API call
result =
  SuperWorker.CircuitBreaker.call(:my_external_service, fn ->
    HTTPoison.get("https://api.example.com/data")
  end)

case result do
  {:ok, response} -> # Handle success
  {:error, :circuit_open} -> # Handle circuit open
  {:error, reason} -> # Handle other errors
end

When the call that trips the threshold fails, the real error is returned; all subsequent calls fail fast with {:error, :circuit_open} until the reset timeout elapses.

Summary

Functions

Call a function protected by the circuit breaker.

Returns a specification to start this module under a supervisor.

Get the current state of the circuit breaker.

Reset the circuit breaker to closed state.

Start a circuit breaker for a named service.

Types

t()

@type t() :: %SuperWorker.CircuitBreaker{
  failure_count: non_neg_integer(),
  failure_threshold: pos_integer(),
  half_open_max_calls: pos_integer(),
  in_flight: non_neg_integer(),
  last_failure_time: integer() | nil,
  name: atom(),
  reset_timeout: pos_integer(),
  state: :closed | :open | :half_open,
  success_count: non_neg_integer()
}

Functions

call(name, fun)

@spec call(atom(), (-> {:ok, any()} | {:error, any()})) ::
  {:ok, any()} | {:error, term()}

Call a function protected by the circuit breaker.

The function runs in the caller process; the breaker only tracks the outcome. Exceptions and exits inside fun are converted to error tuples.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_state(name)

@spec get_state(atom()) :: {:ok, t()} | {:error, :not_found}

Get the current state of the circuit breaker.

reset(name)

@spec reset(atom()) :: :ok | {:error, :not_found}

Reset the circuit breaker to closed state.

start(name, opts \\ [])

@spec start(
  atom(),
  keyword()
) :: {:ok, pid()} | {:error, term()}

Start a circuit breaker for a named service.

The breaker process is linked to the caller.