LemonAi.CircuitBreaker (lemon_ai v0.1.0)

View Source

Circuit breaker GenServer for managing per-provider failure states.

Overview

This module implements the circuit breaker pattern with three states:

  • Closed - Normal operation, requests pass through
  • Open - Too many failures, requests are rejected immediately
  • Half-Open - Testing if service has recovered, limited requests allowed

Usage

# Start the circuit breaker (typically via supervision tree)
{:ok, pid} = LemonAi.CircuitBreaker.start_link(
  provider: :anthropic,
  failure_threshold: 5,
  recovery_timeout: 30_000
)

# Check if circuit is open before making request
if LemonAi.CircuitBreaker.open?(:anthropic) do
  {:error, :circuit_open}
else
  # make request...
  case result do
    {:ok, _} -> LemonAi.CircuitBreaker.record_success(:anthropic)
    {:error, _} -> LemonAi.CircuitBreaker.record_failure(:anthropic)
  end
end

Configuration

  • failure_threshold - Number of failures before opening circuit (default: 5)
  • recovery_timeout - Milliseconds before attempting recovery (default: 30000)
  • provider - Provider identifier (required)

Summary

Functions

Returns a specification to start this module under a supervisor.

Ensure a circuit breaker exists for the provider.

Get current circuit state for debugging/monitoring.

Check if the circuit is open (requests should be rejected).

Record a failed request. May open the circuit.

Record a successful request. Helps close the circuit.

Reset the circuit breaker to closed state. Useful for testing or manual recovery.

Start a circuit breaker for a provider.

Returns milliseconds until the circuit breaker transitions to half-open.

Types

circuit_state()

@type circuit_state() :: :closed | :open | :half_open

provider()

@type provider() :: atom()

state()

@type state() :: %{
  provider: provider(),
  circuit_state: circuit_state(),
  failure_count: non_neg_integer(),
  failure_threshold: pos_integer(),
  recovery_timeout: pos_integer(),
  last_failure_time: integer() | nil,
  last_failure_reason: term() | nil,
  success_count_in_half_open: non_neg_integer()
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

ensure_started(provider, opts \\ [])

@spec ensure_started(
  provider(),
  keyword()
) :: {:ok, pid()} | {:error, term()}

Ensure a circuit breaker exists for the provider.

Starts a breaker under LemonAi.ProviderSupervisor when available.

get_state(provider)

@spec get_state(provider()) :: {:ok, map()} | {:error, :not_found}

Get current circuit state for debugging/monitoring.

open?(provider)

@spec open?(provider()) :: boolean()

Check if the circuit is open (requests should be rejected).

Returns true if the circuit is open, false if closed or half-open. In half-open state, limited requests are allowed through.

record_failure(provider, reason \\ :unknown)

@spec record_failure(provider(), term()) :: :ok

Record a failed request. May open the circuit.

record_success(provider)

@spec record_success(provider()) :: :ok

Record a successful request. Helps close the circuit.

reset(provider)

@spec reset(provider()) :: :ok

Reset the circuit breaker to closed state. Useful for testing or manual recovery.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Start a circuit breaker for a provider.

Options

  • :provider - Provider identifier (required)
  • :failure_threshold - Failures before opening (default: 5)
  • :recovery_timeout - Recovery wait time in ms (default: 30000)

time_until_recovery(provider)

@spec time_until_recovery(provider()) :: non_neg_integer()

Returns milliseconds until the circuit breaker transitions to half-open.

Returns 0 when the circuit is closed or already half-open.