nodus-circuit-breaker
Three-state circuit breaker (closed → open → half-open) with async support and an optional LLM provider adapter.
Zero required dependencies — pure Python standard library. Optional
Prometheus metrics via the [metrics] extra.
Status: v0.1.0 — prepared, not yet published.
Install
pip install nodus-circuit-breaker
# With optional Prometheus metrics:
pip install "nodus-circuit-breaker[metrics]"
What it provides
| Component | Purpose |
|---|---|
CircuitBreaker |
Three-state machine with sync and async call wrappers |
CircuitState |
CLOSED / OPEN / HALF_OPEN enum |
CircuitOpenError |
Raised when the circuit rejects a call |
LLMClient |
Structural protocol for LLM provider clients |
CircuitBreakerLLMClient |
Wraps any LLMClient with a CircuitBreaker |
LLMCallError / LLMCircuitOpenError |
Normalized LLM error types |
Basic usage
from nodus_circuit_breaker import CircuitBreaker, CircuitOpenError
cb = CircuitBreaker(
"my-service",
failure_threshold=3, # open after 3 consecutive failures
recovery_timeout_secs=60, # wait 60s before trying half-open
)
try:
result = cb.call(my_function, arg1, arg2)
except CircuitOpenError:
result = fallback_value
Async
result = await cb.async_call(my_async_function, arg1, arg2)
State machine
CLOSED ──(failures ≥ threshold)──► OPEN
OPEN ──(timeout elapsed)───────► HALF_OPEN
HALF_OPEN ──(success)────────────► CLOSED
HALF_OPEN ──(failure)────────────► OPEN
- CLOSED — normal operation; failures are counted.
- OPEN — all calls immediately raise
CircuitOpenError; no upstream calls made. - HALF_OPEN — one probe call allowed; success closes, failure reopens.
State change callback
def on_change(name: str, previous: str, new: str) -> None:
print(f"{name}: {previous} → {new}")
cb = CircuitBreaker("svc", on_state_change=on_change)
Prometheus integration via callback
from prometheus_client import CollectorRegistry, Gauge
registry = CollectorRegistry()
cb_gauge = Gauge("cb_state", "Circuit breaker state", ["name"], registry=registry)
def prometheus_hook(name: str, prev: str, new: str) -> None:
value = {"closed": 0, "half_open": 1, "open": 2}.get(new, -1)
cb_gauge.labels(name=name).set(value)
cb = CircuitBreaker("my-service", on_state_change=prometheus_hook)
Requires pip install "nodus-circuit-breaker[metrics]".
LLM provider adapter
from nodus_circuit_breaker import CircuitBreakerLLMClient, LLMCircuitOpenError
# Wrap any LLMClient-compliant provider (OpenAI, Anthropic, etc.)
client = CircuitBreakerLLMClient(my_provider_client, provider="openai")
try:
reply = client.chat([{"role": "user", "content": "hello"}])
except LLMCircuitOpenError:
reply = "Service temporarily unavailable."
LLMClient is a structural protocol — any object with chat(messages, **kwargs) satisfies it.
Inspecting state
cb.state # CircuitState.CLOSED / OPEN / HALF_OPEN
cb.failure_count # int
cb.name # str
cb.reset() # force-close the circuit
Design
- No required dependencies. Core breaker and LLM adapter are pure stdlib.
Prometheus integration is opt-in via
[metrics]extra. - Thread-safe. State transitions use
threading.Lock. - Callback-driven observability.
on_state_changedecouples metrics from the breaker itself.
Development
pip install -e ".[dev]"
pytest tests/ -q
License
MIT — see LICENSE.
Metadata
Release files for nodus-circuit-breaker 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nodus_circuit_breaker-0.1.0.tar.gz | 8.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nodus_circuit_breaker-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.8 kB
Release files / nodus_circuit_breaker-0.1.0.tar.gz
| Download URL | nodus_circuit_breaker-0.1.0.tar.gz |
|---|---|
| Size | 8.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8c9cc752768bf5f30bb24a1561f77627c61789ae74e5fe6f0c5a73a488af8e47
|
|
BLAKE2b-256 checksum How to use checksums |
6a13f6050c559308a6e3bd61c4237ac08733e66a9b4c457e414e49d4a099cd97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / nodus_circuit_breaker-0.1.0-py3-none-any.whl
| Download URL | nodus_circuit_breaker-0.1.0-py3-none-any.whl |
|---|---|
| Size | 7.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac0e7aa23e23de419e8971c2d68c13e1a0b1cc1597b4c751e6341ffa29d1650b
|
|
BLAKE2b-256 checksum How to use checksums |
dd41175399ac92742def9eb3005c34c3898ceceb44eded5fbe9de63a663133f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|