circuit

Types

pub type ActorState {
  ActorState(
    circuit_state: CircuitState,
    window: List(CallResult),
    config: Config,
  )
}

Constructors

The error type returned by call/2.

  • CircuitOpen — the circuit is currently Open and the call was blocked without executing the function.
  • CallFailed(reason) — the circuit was not open, the function ran, but it returned Failure(reason).
pub type CallError {
  CircuitOpen
  CallFailed(reason: String)
}

Constructors

  • CircuitOpen
  • CallFailed(reason: String)

The result of a single call through the circuit breaker.

Pass one of these to record_result/2, or return one from the function you pass to call/2.

  • Success — the call succeeded.
  • Failure(reason) — the call failed, with a string describing why.
pub type CallResult {
  Success
  Failure(reason: String)
}

Constructors

  • Success
  • Failure(reason: String)

An opaque handle to a running circuit breaker process.

Obtain one via start/1. Pass it to call/2, state/1, reset/1, and record_result/2. The internals (actor Subject, message protocol) are hidden — interact with the breaker only through the public API.

pub opaque type CircuitBreaker

Represents the three states a circuit breaker can be in.

  • Closed — normal operation. Calls pass through and results are tracked.
  • Open — tripped state. All calls are blocked immediately and return Error(CircuitOpen).
  • HalfOpen — recovery probe state. A single call is allowed through to test whether the downstream service has recovered. Success closes the circuit; failure trips it back to Open.
pub type CircuitState {
  Closed
  Open
  HalfOpen
}

Constructors

  • Closed
  • Open
  • HalfOpen

Configuration for a circuit breaker.

Use new/0 and the builder functions to construct a Config rather than using this constructor directly.

pub type Config {
  Config(
    failure_threshold: Int,
    window_size: Int,
    reset_timeout: Int,
  )
}

Constructors

  • Config(
      failure_threshold: Int,
      window_size: Int,
      reset_timeout: Int,
    )
pub type Message {
  RecordResult(CallResult)
  GetState(process.Subject(CircuitState))
  Reset
}

Constructors

Values

pub fn call(
  breaker: CircuitBreaker,
  f: fn() -> CallResult,
) -> Result(Nil, CallError)

Runs f through the circuit breaker and records its result.

  • If the circuit is Open, f is not called and Error(CircuitOpen) is returned immediately.
  • If the circuit is Closed or HalfOpen, f is called. A Success result returns Ok(Nil). A Failure(reason) result returns Error(CallFailed(reason)). Either way, the result is automatically recorded against the sliding window.

Example

case circuit.call(breaker, fn() {
  case fetch_user(id) {
    Ok(_) -> circuit.Success
    Error(_) -> circuit.Failure("fetch failed")
  }
}) {
  Ok(Nil) -> // call succeeded
  Error(circuit.CircuitOpen) -> // blocked — try a fallback
  Error(circuit.CallFailed(reason)) -> // call ran but failed
}
pub fn failure_threshold(config: Config, value: Int) -> Config

Sets the number of failures within the sliding window required to trip the circuit from Closed to Open.

A lower value makes the breaker more sensitive. A higher value tolerates more failures before tripping.

pub fn new() -> Config

Returns a Config with sensible production defaults:

  • failure_threshold: 5
  • window_size: 10
  • reset_timeout: 30_000ms (30 seconds)

These defaults are a reasonable starting point. Tune them for your workload using failure_threshold/2, window_size/2, and reset_timeout/2.

Example

let config =
  circuit.new()
  |> circuit.failure_threshold(3)
  |> circuit.window_size(5)
  |> circuit.reset_timeout(10_000)
pub fn record_result(
  breaker: CircuitBreaker,
  result: CallResult,
) -> Nil

Records a CallResult against the breaker without running a function.

Use this when you are managing the call yourself and just want to inform the breaker of the outcome. For the common case of wrapping a function, prefer call/2 instead.

pub fn reset(breaker: CircuitBreaker) -> Nil

Manually resets the breaker to Closed and clears the sliding window.

Useful in tests or admin tooling. In normal operation the breaker manages its own state — you should rarely need to call this directly.

pub fn reset_timeout(config: Config, value: Int) -> Config

Sets how long (in milliseconds) the circuit stays Open before transitioning to HalfOpen to probe for recovery.

A shorter timeout means faster recovery attempts. A longer timeout gives the downstream service more time to recover before being probed.

pub fn start(
  config: Config,
) -> Result(CircuitBreaker, actor.StartError)

Starts a new circuit breaker process with the given Config.

Returns Ok(CircuitBreaker) on success, or Error(actor.StartError) if the underlying OTP actor fails to start.

Example

let assert Ok(breaker) =
  circuit.new()
  |> circuit.failure_threshold(5)
  |> circuit.start()
pub fn state(breaker: CircuitBreaker) -> CircuitState

Returns the current CircuitState of the breaker (Closed, Open, or HalfOpen).

This is a synchronous call to the actor — it blocks briefly until the actor responds.

pub fn transition(
  state: CircuitState,
  result: CallResult,
  failures: Int,
  config: Config,
) -> CircuitState
pub fn window_size(config: Config, value: Int) -> Config

Sets the size of the sliding window — the number of most recent calls that are tracked when calculating the failure rate.

For example, a window_size of 10 means only the last 10 call results are considered. Older results are discarded automatically.

Search Document