Saltar a contenido

dorm.contrib.circuit_breaker

Circuit breaker per-name: CLOSED → OPEN → HALF_OPEN state machine. Sync and async context-manager forms.

See Circuit breaker for recipes.

API

dorm.contrib.circuit_breaker.CircuitBreaker

Process-local circuit breaker keyed by an arbitrary name.

Construct directly for advanced use cases; most callers prefer the :func:circuit_breaker factory which memoises one instance per name so different code paths sharing a database alias share state.

allow() -> bool

Return True when a call may proceed; False otherwise.

Half-open transitions are made here so the very next call to allow() after the open window elapses returns True.

reset() -> None

Forcibly return the breaker to CLOSED. Useful in tests.

aprotect() async

Async context manager equivalent to with breaker:.

Awaits nothing inside the wrapper itself — exists so async code can use the same breaker without juggling sync/async boundary helpers.

Notable nuance: asyncio.CancelledError is not counted as a breaker failure. Cancellation usually comes from a client disconnect or a task timeout, neither of which signals a DB problem; counting them would prematurely trip the breaker under heavy graceful-shutdown traffic.

dorm.contrib.circuit_breaker.circuit_breaker(name: str, *, failure_threshold: int = 5, open_window_s: float = 30.0) -> CircuitBreaker

Return the process-shared :class:CircuitBreaker for name.

Tuning parameters apply only the first time a breaker is created under a given name — later calls return the existing instance and ignore the kwargs (so different call sites can't fight over knobs). Use :func:reset_circuit_breakers in test setUp.

dorm.contrib.circuit_breaker.CircuitOpenError

Bases: DatabaseError

Raised by an open breaker instead of executing the wrapped call.

Subclasses :class:dorm.exceptions.DatabaseError so callers that already catch generic DB errors degrade gracefully — it is, after all, a database-availability signal.

dorm.contrib.circuit_breaker.CircuitState

Bases: Enum

dorm.contrib.circuit_breaker.reset_circuit_breakers() -> None

Drop every registered breaker. Safe to call between tests so a breaker tripped by one test doesn't bleed into the next.

dorm.contrib.circuit_breaker.get_state(name: str) -> dict[str, Any]

Return a snapshot of one breaker's state for monitoring / Prometheus exposition. Keys: state, failures, opened_at (monotonic, None if not open).