A modern circuit breaker for Python: sync + async, sliding-window rate, slow-call detection, type-safe API.
Project description
interlock
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
CircuitBreakerdetects coroutine callables and dispatches to the right path — noSync*/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+TypeVardecorators preserve the wrapped signature and its sync/async nature; shipspy.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/:
- Getting started
- Configuration
- States & manual control
- Failure classification
- Observability
- Timeout
- httpx2 integration
- API reference
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea43597541c7e2ac0a5625e90121809753c7275d93ea274be7e305f740a597d2
|
|
| MD5 |
65ec8ce0d9c7d6dbb208888cf7477496
|
|
| BLAKE2b-256 |
906a0106dddba70d1d67cf8cfbfc6510dfc238f5c120a969fc2aa191d63517aa
|
Provenance
The following attestation bundles were made for interlock_cb-1.0.0.tar.gz:
Publisher:
release.yml on bagowix/interlock
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
interlock_cb-1.0.0.tar.gz -
Subject digest:
ea43597541c7e2ac0a5625e90121809753c7275d93ea274be7e305f740a597d2 - Sigstore transparency entry: 1977505429
- Sigstore integration time:
-
Permalink:
bagowix/interlock@76740b9fe7572a57e2a45a3a51f862e92d51a6c0 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/bagowix
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@76740b9fe7572a57e2a45a3a51f862e92d51a6c0 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3884c839c2b345466c7a063861b0e5f23ebe895d5358d5a9f85ebfc73f46a375
|
|
| MD5 |
1b9e7b2f81a93896bf4efde0407c5cbb
|
|
| BLAKE2b-256 |
63426f6a5cfb3b97911737bd29440981900a93fed6ac82e1bae6d0e891d8d6fd
|
Provenance
The following attestation bundles were made for interlock_cb-1.0.0-py3-none-any.whl:
Publisher:
release.yml on bagowix/interlock
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
interlock_cb-1.0.0-py3-none-any.whl -
Subject digest:
3884c839c2b345466c7a063861b0e5f23ebe895d5358d5a9f85ebfc73f46a375 - Sigstore transparency entry: 1977505538
- Sigstore integration time:
-
Permalink:
bagowix/interlock@76740b9fe7572a57e2a45a3a51f862e92d51a6c0 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/bagowix
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@76740b9fe7572a57e2a45a3a51f862e92d51a6c0 -
Trigger Event:
push
-
Statement type: