CCXT.CircuitBreaker (ccxt_client v0.6.1)

Copy Markdown View Source

Per-exchange circuit breakers using the :fuse Erlang library.

Prevents cascade failures when exchanges are down. Each exchange has isolated state — binance down does not affect bybit.

How It Works

  1. Each exchange gets its own fuse named :ccxt_fuse_<exchange_id>
  2. Fuses are installed lazily on first request
  3. After N failures within M milliseconds, the circuit opens
  4. Opened circuits reject requests immediately (fast fail)
  5. After reset timeout, circuit closes and allows requests again

What Triggers the Circuit

ResponseMelts?Reason
HTTP 500+YesServer error
TimeoutsYesServer unresponsive
Connection refusedYesServer unavailable
HTTP 429NoHandled by rate limiter
HTTP 4xxNoClient error, not server issue

Configuration

config :ccxt_client, :circuit_breaker,
  enabled: true,
  max_failures: 5,
  window_ms: 10_000,
  reset_ms: 15_000

Summary

Functions

Returns status of all installed circuit breakers.

Checks if requests are allowed for an exchange.

Returns circuit breaker configuration.

Records a failed request. Enough melts within the window opens the circuit.

Records the result of a request using should_melt?/1 logic.

Records a successful request. Success prevents further melts.

Resets a circuit breaker for an exchange.

Resets a circuit breaker, raising on error.

Determines if a response should trip the circuit breaker.

Returns the status of a circuit breaker for an exchange.

Functions

all_statuses()

@spec all_statuses() :: %{required(String.t()) => :ok | :blown}

Returns status of all installed circuit breakers.

check(exchange_id)

@spec check(String.t()) :: :ok | :blown

Checks if requests are allowed for an exchange.

Installs the fuse lazily if not already installed.

config()

@spec config() :: %{
  enabled: boolean(),
  max_failures: pos_integer(),
  window_ms: pos_integer(),
  reset_ms: pos_integer()
}

Returns circuit breaker configuration.

record_failure(exchange_id)

@spec record_failure(String.t()) :: :ok

Records a failed request. Enough melts within the window opens the circuit.

record_result(exchange_id, result)

@spec record_result(String.t(), term()) :: :ok

Records the result of a request using should_melt?/1 logic.

Pass the raw result from Req ({:ok, %Req.Response{}} or {:error, reason}).

record_success(exchange_id)

@spec record_success(String.t()) :: :ok

Records a successful request. Success prevents further melts.

reset(exchange_id)

@spec reset(String.t()) :: :ok | {:error, :not_found}

Resets a circuit breaker for an exchange.

reset!(exchange_id)

@spec reset!(String.t()) :: :ok

Resets a circuit breaker, raising on error.

should_melt?(arg1)

@spec should_melt?(term()) :: boolean()

Determines if a response should trip the circuit breaker.

Melts on: HTTP 500+, transport errors. Does NOT melt on: HTTP 429, HTTP 4xx, successful responses.

status(exchange_id)

@spec status(String.t()) :: :ok | :blown | :not_installed

Returns the status of a circuit breaker for an exchange.

  • :ok — circuit closed, requests allowed
  • :blown — circuit open, requests rejected
  • :not_installed — no fuse yet (no requests made)