Skip to content

Integrations

interlock plugs into the HTTP client, framework or retry library you already use — you configure thresholds once and the breaker applies per host (or per named dependency) with no decorators in call sites.

Supported integrations

Integration Extra What you get
FastAPI interlock-cb[fastapi] Depends-injected breakers and a CircuitOpenError → 503 + Retry-After handler
Litestar interlock-cb[litestar] Provide-injected breakers and a CircuitOpenError → 503 + Retry-After handler (Litestar ≥ 2.23)
httpx2 interlock-cb[httpx2] CircuitBreakerTransport / AsyncCircuitBreakerTransport — per-host breaker at the transport level
httpx interlock-cb[httpx] CircuitBreakerTransport / AsyncCircuitBreakerTransport — per-host transport for httpx clients
aiohttp interlock-cb[aiohttp] CircuitBreakerMiddleware — per-host breaker as a client middleware (aiohttp ≥ 3.12)
requests interlock-cb[requests] CircuitBreakerAdapter — per-host breaker mounted on a Session
LLM SDKs — (recipe) Guard OpenAI / Anthropic SDK calls with a breaker + bounded retries
tenacity interlock-cb[tenacity] Retry × breaker glue: stop retrying when the circuit opens, or wait exactly until the next probe
Redis interlock-cb[redis] Shared breaker state across processes with graceful degradation
Flask / Django — (recipe) Map CircuitOpenError to 503 + Retry-After in other web frameworks

How integrations are built

Every integration follows the same rules, so learning one means knowing all:

  • Native extension points only. A transport (httpx2/httpx), a client middleware (aiohttp), an adapter (requests), an exception handler (FastAPI). No monkey-patching, no private APIs — an integration survives minor releases of its host library.
  • One breaker per host. HTTP integrations key breakers by request host: a failing api.a never trips api.b. Breakers are created lazily in a shared Registry.
  • Safe rollout before enforcement. Pass initial_state=State.METRICS_ONLY to record real traffic without rejecting it. The state is applied before each lazy breaker serves its first request; deploy a new integration with CLOSED after tuning thresholds.
  • One classification model. Responses are classified by an HttpStatusClassifier — by default the canonical retryable set (429, 500, 502, 503, 504) plus every non-excluded transport exception counts as a failure, while 4xx client mistakes do not. Exceptions the caller caused say nothing about the dependency's health, so each integration excludes the ones its own library raises inside the guarded call: UnsupportedProtocol / LocalProtocolError for httpx2 and httpx, InvalidURL for requests, nothing for aiohttp (it rejects malformed URLs before the middleware chain runs). Pass HttpStatusClassifier(failure_statuses={...}, excluded_exceptions=(...)) or your own FailureClassifier to change the policy.
  • One rejection signal, in two dialects. An open circuit always raises CircuitOpenError — carrying the breaker name, a retry_after estimate and the last recorded failure — before a connection is attempted. Each HTTP client integration raises a subclass that is also a native error of that library, so an application's existing degradation path catches it: CircuitOpenTransportError (an httpx.TransportError for the httpx integration, an httpx2.TransportError for the httpx2 one), CircuitOpenClientError (an aiohttp.ClientConnectionError), CircuitOpenRequestError (a requests.exceptions.ConnectionError). The host base is always the broadest "the request never completed" type, never a leaf such as ConnectError — leaves are what retry predicates key on, and retrying a rejection only burns an attempt against a circuit that is still open.
  • Zero-dependency core. Integrations live in interlock.integrations.* as optional extras; import interlock itself never pulls anything beyond the standard library.
  • Explicit ownership and teardown. Transports and adapters close their native connection resources together with their breaker registry. The aiohttp middleware exposes aclose() because ClientSession does not own middleware resources.

Support tiers

  • Tier 1 — shipped code. Modules under interlock.integrations.*, covered by the test suite and CI against both the minimum supported and the latest version of the host library. Semver applies.
  • Tier 2 — recipes. Documented, runnable patterns (LLM SDKs, Flask/Django) that need no dedicated glue code. They can graduate to Tier 1 when demand shows up.

Missing an integration — gRPC, SQLAlchemy, Kafka, Celery? Open an issue: the next wave is prioritised by demand.