Skip to main content

Three-state circuit breaker with async support and optional LLM adapter

Project description

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_change decouples metrics from the breaker itself.

Development

pip install -e ".[dev]"
pytest tests/ -q

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nodus_circuit_breaker-0.1.0.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nodus_circuit_breaker-0.1.0-py3-none-any.whl (7.9 kB view details)

Uploaded Python 3

File details

Details for the file nodus_circuit_breaker-0.1.0.tar.gz.

File metadata

  • Download URL: nodus_circuit_breaker-0.1.0.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for nodus_circuit_breaker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8c9cc752768bf5f30bb24a1561f77627c61789ae74e5fe6f0c5a73a488af8e47
MD5 7860e170b69ca740339937da52919175
BLAKE2b-256 6a13f6050c559308a6e3bd61c4237ac08733e66a9b4c457e414e49d4a099cd97

See more details on using hashes here.

File details

Details for the file nodus_circuit_breaker-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for nodus_circuit_breaker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ac0e7aa23e23de419e8971c2d68c13e1a0b1cc1597b4c751e6341ffa29d1650b
MD5 f0e80bfc621607e7edb0745d4dafd91e
BLAKE2b-256 dd41175399ac92742def9eb3005c34c3898ceceb44eded5fbe9de63a663133f4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page