Skip to main content

A modern circuit breaker for Python: sync + async, sliding-window rate, slow-call detection, type-safe API.

Project description

interlock

CI PyPI Python versions License: MIT

A modern circuit breaker for Python — sync and async in a single class, sliding-window rate and slow-call detection, a type-safe API, and transparent integrations at the transport level.

Why interlock

  • Sync and async, one class. A single CircuitBreaker detects coroutine callables and dispatches to the right path — no Sync*/Async* twins.
  • Sliding windows by rate. Both count-based and time-based windows, not the naive consecutive-failure counter found elsewhere in the ecosystem.
  • Slow-call detection. Treat calls slower than a threshold as failures — not available in any other Python circuit breaker.
  • Type-safe. ParamSpec + TypeVar decorators preserve the wrapped signature and its sync/async nature; ships py.typed, passes mypy and pyright in strict mode.
  • Zero-dependency core. Standard library only; everything external lives in optional extras (interlock-cb[otel], interlock-cb[httpx2]).

Installation

uv add interlock-cb          # or: pip install interlock-cb

Optional extras:

uv add 'interlock-cb[otel]'    # OpenTelemetry metrics listener
uv add 'interlock-cb[httpx2]'  # per-host httpx2 transport

Quickstart

Protect a callable three ways over the one call() primitive.

from interlock import CircuitBreaker, Config

breaker = CircuitBreaker(
    name='payments',
    config=Config(failure_rate_threshold=0.5, minimum_number_of_calls=20),
)

# 1. Decorator — preserves the signature and sync/async nature.
@breaker
def charge(amount: int) -> str:
    return gateway.charge(amount)

# 2. breaker.call — the breaker runs the callable.
result = breaker.call(gateway.charge, 100)

# 3. Context manager — guards a block (exceptions + duration only).
with breaker:
    gateway.charge(100)

The same instance works for async — the decorator and call detect a coroutine function, and the instance is also an async context manager:

@breaker
async def fetch(url: str) -> bytes:
    return await client.get(url)

async with breaker:
    await client.get(url)

When the circuit is open, the call is rejected with CircuitOpenError, which carries the breaker name, an estimate of when the next probe is allowed, and the last recorded failure:

from interlock import CircuitOpenError

try:
    breaker.call(gateway.charge, 100)
except CircuitOpenError as exc:
    print(exc.breaker_name, exc.retry_after, exc.last_failure)

httpx2 integration

Apply a breaker per host transparently, with no decorators in call sites:

import httpx2
from interlock.httpx2 import CircuitBreakerTransport

transport = CircuitBreakerTransport(httpx2.HTTPTransport())
client = httpx2.Client(transport=transport)

By default, transport exceptions and the canonical retryable statuses (429, 500, 502, 503, 504) count as failures; 4xx client errors do not.

Documentation

Full guides, integration recipes and the API reference live in docs/:

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md for the local setup and the checks a change must pass, and CODE_OF_CONDUCT.md for community expectations. Security issues: please follow SECURITY.md.

License

interlock is released under the MIT 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

interlock_cb-1.0.0.tar.gz (103.5 kB view details)

Uploaded Source

Built Distribution

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

interlock_cb-1.0.0-py3-none-any.whl (27.3 kB view details)

Uploaded Python 3

File details

Details for the file interlock_cb-1.0.0.tar.gz.

File metadata

  • Download URL: interlock_cb-1.0.0.tar.gz
  • Upload date:
  • Size: 103.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for interlock_cb-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ea43597541c7e2ac0a5625e90121809753c7275d93ea274be7e305f740a597d2
MD5 65ec8ce0d9c7d6dbb208888cf7477496
BLAKE2b-256 906a0106dddba70d1d67cf8cfbfc6510dfc238f5c120a969fc2aa191d63517aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for interlock_cb-1.0.0.tar.gz:

Publisher: release.yml on bagowix/interlock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file interlock_cb-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: interlock_cb-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 27.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for interlock_cb-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3884c839c2b345466c7a063861b0e5f23ebe895d5358d5a9f85ebfc73f46a375
MD5 1b9e7b2f81a93896bf4efde0407c5cbb
BLAKE2b-256 63426f6a5cfb3b97911737bd29440981900a93fed6ac82e1bae6d0e891d8d6fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for interlock_cb-1.0.0-py3-none-any.whl:

Publisher: release.yml on bagowix/interlock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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