AgentSessionManager.Routing.CircuitBreaker (AgentSessionManager v0.8.0)

Copy Markdown View Source

Pure-functional circuit breaker for provider health tracking.

The circuit breaker maintains three states:

  • :closed — normal operation; requests are allowed.
  • :open — too many failures; requests are blocked until cooldown expires.
  • :half_open — cooldown expired; limited probe requests are allowed to test recovery.

State Transitions

:closed --(failure threshold reached)--> :open
:open   --(cooldown expires)-----------> :half_open
:half_open --(probe succeeds)----------> :closed
:half_open --(probe fails)-------------> :open

Usage

This module is a pure data structure with no side effects or processes. It is intended to be stored in router state per adapter.

cb = CircuitBreaker.new(failure_threshold: 3, cooldown_ms: 30_000)
cb = CircuitBreaker.record_failure(cb)
CircuitBreaker.allowed?(cb)  # true (still below threshold)

Configuration

  • failure_threshold — number of consecutive failures to trigger open state (default: 5)
  • cooldown_ms — how long to stay open before transitioning to half-open (default: 30_000)
  • half_open_max_probes — probe attempts allowed in half-open before requiring success or reopening (default: 1)

Summary

Functions

Returns whether a request is allowed through the circuit breaker.

Checks and potentially transitions the state based on elapsed time.

Returns the current failure count.

Creates a new circuit breaker in :closed state.

Records a failed request.

Records a successful request.

Returns the current circuit breaker state.

Returns a map summary of the circuit breaker state.

Types

state()

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

t()

@type t() :: %AgentSessionManager.Routing.CircuitBreaker{
  cooldown_ms: non_neg_integer(),
  failure_count: non_neg_integer(),
  failure_threshold: pos_integer(),
  half_open_max_probes: pos_integer(),
  half_open_probe_count: non_neg_integer(),
  opened_at_ms: integer() | nil,
  state: state()
}

Functions

allowed?(cb)

@spec allowed?(t()) :: boolean()

Returns whether a request is allowed through the circuit breaker.

  • :closed — always allowed
  • :open — allowed only if cooldown has expired (probe)
  • :half_open — allowed if probe count is below max

check_state(cb)

@spec check_state(t()) :: t()

Checks and potentially transitions the state based on elapsed time.

  • :open with expired cooldown → :half_open
  • All other states → no change

failure_count(circuit_breaker)

@spec failure_count(t()) :: non_neg_integer()

Returns the current failure count.

new(opts \\ [])

@spec new(keyword()) :: t()

Creates a new circuit breaker in :closed state.

Options

  • :failure_threshold — failures before opening (default: 5)
  • :cooldown_ms — cooldown period in milliseconds (default: 30_000)
  • :half_open_max_probes — max probes in half-open (default: 1)

record_failure(cb)

@spec record_failure(t()) :: t()

Records a failed request.

  • :closed — increments failure count; opens if threshold reached
  • :half_open — reopens immediately
  • :open — stays open (no-op)

record_success(cb)

@spec record_success(t()) :: t()

Records a successful request.

  • :closed — resets failure count
  • :half_open — transitions to :closed
  • :open — resets to :closed (unexpected but safe)

state(circuit_breaker)

@spec state(t()) :: state()

Returns the current circuit breaker state.

to_map(cb)

@spec to_map(t()) :: map()

Returns a map summary of the circuit breaker state.