Per-server circuit breaker backed by ETS.
Isolates a failing Nominatim server by short-circuiting requests after a
configurable failure threshold. Uses a lazy half-open transition — no timers,
no GenServer. The reset_ms window is checked synchronously when an open
breaker is probed.
States
:closed— normal operation, requests pass through.:open— failures have exceededthreshold; requests are rejected untilreset_mselapses.:half_open— the reset window has elapsed; the next request is let through as a probe. On success →:closed, on failure →:open.
Configuration
Set circuit_breaker to configure per-server protection:
# Enable with defaults (threshold: 5, reset_ms: 30_000)
circuit_breaker: true
# Full control
circuit_breaker: [threshold: 3, reset_ms: 60_000]
# Disabled (default)
circuit_breaker: falseFailures counted: transport errors, 5xx responses, and retry exhaustion.
Telemetry
Emits [:ex_nominatim, :circuit_breaker, :state_change] on every state
transition with metadata %{base_url: String.t(), from: atom, to: atom, reason: atom}.
Summary
Functions
Check whether a request to base_url is allowed.
Record a failed request to base_url.
Record a successful request to base_url.
Functions
Check whether a request to base_url is allowed.
Returns :ok when the breaker is:
:closed— normal operation.:half_open— probe request allowed.
Returns {:error, %{code: :circuit_open, descr: _, retry_after_ms: _}} when
the breaker is :open and the reset window has not elapsed.
Record a failed request to base_url.
Increments the failure counter and may transition the breaker from
:closed → :open if the threshold is exceeded, or from :half_open →
:open (probe failure).
Respects the circuit_breaker config option to determine threshold.
Safe to call for every failed response / transport error.
Record a successful request to base_url.
Resets the breaker to :closed with zero failure count. Idempotent —
safe to call unconditionally after every successful response.