Asynchronous HTTP client for Python engineered to tolerate downstream service outages, network instability, and latency spikes. It implements proven resilience patterns including Circuit Breakers, Retry Policies, Fallback Mechanisms, and a Distributed Failure Store to enable reliable service-to-service communication.
Built on top of httpx, the library is designed for modern distributed systems where resilience is a first-class requirement.
- Circuit Breaker Pattern β Prevents cascading failures using a strict state machine (
CLOSED,OPEN,HALF-OPEN). - Distributed Failure Store β Share circuit state and failure metrics across workers and service instances.
- Automatic Retries β Configurable retry budgets with exponential backoff for transient failures.
- Graceful Fallbacks β Return degraded responses or execute alternative logic instead of surfacing raw exceptions.
- Fully Asynchronous β Built on
httpxfor high-concurrency, non-blocking I/O. - Pluggable Components β Storage and resilience behavior can be customized to fit different deployment environments.
- Production Ready β Suitable for microservices, containerized workloads, and distributed deployments.
The coordination of request delivery, state checking, retries, and fallback execution is modeled in our system architecture.
π View System Architecture Diagram π View Request Sequence Flow Diagram
The client implements a fully compliant circuit breaker state machine with lazy cooldown transitions and probe request gating.
Requests flow normally.
- Successful requests reset failure counters.
- Consecutive failures are tracked.
- Reaching the configured threshold transitions the circuit to OPEN.
Requests fail immediately without contacting the downstream service.
- Prevents latency amplification and resource exhaustion.
- Remains open for the configured cooldown period.
- Automatically transitions to HALF-OPEN after cooldown expires.
Allows a limited number of probe requests.
- Successful probes close the circuit.
- Any failed probe immediately reopens the circuit.
- Prevents unstable services from causing repeated outages.
Install the package via pip or your favorite package manager:
pip install ad-tech-inc-resilient-httpOr using uv:
uv add ad-tech-inc-resilient-httpimport asyncio
import redis.asyncio as redis
from resilient_http_client import (
FailureStore,
ResilientHttpClient,
)
async def main():
# Example using Redis-backed storage
redis_client = redis.Redis(
host="localhost",
port=6379,
decode_responses=True,
)
store = FailureStore(
redis=redis_client,
service="stripe_payment",
)
async with ResilientHttpClient(
service="stripe_payment",
store=store,
) as client:
response = await client.request(
method="POST",
url="https://api.stripe.com/v1/charges",
json={
"amount": 2000,
"currency": "usd",
},
)
# The request returns a raw httpx.Response object on success
if hasattr(response, "json"):
print("Status:", response.status_code)
print("Response Data:", response.json())
else:
# Fallback values returned as a dict
print("Fallback Response:", response)
if __name__ == "__main__":
asyncio.run(main())Customize resilience behavior through ResilienceConfig.
from resilient_http_client import ResilienceConfig
config = ResilienceConfig(
failure_threshold=5,
cooldown=30,
max_retries=3,
timeout=5.0,
half_open_max_calls=1,
half_open_successes_needed=1,
)
client = ResilientHttpClient(
service="my-api",
store=store,
config=config,
)| Parameter | Type | Default | Description |
|---|---|---|---|
failure_threshold |
int |
5 |
Consecutive failures required to open the circuit |
cooldown |
int |
30 |
Seconds before an open circuit transitions to half-open |
max_retries |
int |
3 |
Number of retry attempts before failure |
timeout |
float |
5.0 |
Request timeout in seconds |
half_open_max_calls |
int |
1 |
Maximum probe requests allowed while half-open |
half_open_successes_needed |
int |
1 |
Successful probes required to close the circuit |
Prevents repeated requests to unhealthy downstream services.
States:
- Closed β Requests flow normally.
- Open β Requests fail immediately.
- Half-Open β Limited recovery probes are allowed.
Automatically retries transient failures using configurable exponential backoff.
Typical retry conditions include:
- HTTP 5xx responses
- Connection failures
- Network timeouts
Fallbacks are executed when:
- The circuit is open.
- Retry attempts are exhausted.
- A non-retryable failure occurs.
Persists resilience state used by the circuit breaker.
Responsibilities include:
- Failure counters
- Circuit state
- Cooldown timestamps
- Cross-worker coordination
The library includes a Redis-backed implementation and can be extended with custom storage backends.
src/
βββ resilient_http_client/
βββ __init__.py
βββ client.py
βββ circuit_breaker.py
βββ config.py
βββ failure_store.py
βββ fallback.py
βββ http.py
βββ retry.py
βββ types.py
tests/
βββ test_circuit_breaker.py
βββ test_failure_store.py
βββ test_fallback.py
βββ test_flaky_resilience.py
βββ test_integration.py
βββ test_retry_policy.py
- π°οΈ
client.pyβ Main orchestration layer. - π
circuit_breaker.pyβ Circuit breaker state machine. - ποΈ
failure_store.pyβ Distributed state management. - π
retry.pyβ Retry policy implementation. - π
fallback.pyβ Fallback registration and execution. - βοΈ
config.pyβ Configuration definitions. - π
types.pyβ Shared enums and type definitions. - π
http.pyβ HTTP request execution layer.
Run the full test suite:
uv run pytest- Failure tracking
- Circuit opening thresholds
- Cooldown transitions
- Half-open probe gating
- Recovery behavior
- Retry policies
- Distributed state persistence
- Fallback execution paths
The examples/ directory contains complete demonstrations and integrations.
-
Start Redis:
docker compose up -d
-
Run the example:
PYTHONPATH=. uv run python examples/slack_example.py
Available examples:
fastapi_integration.pysimulate_outage.pyslack_example.pystripe_example.py
- Service-to-service communication
- Third-party API integrations
- Payment gateways
- Authentication providers
- Event-driven systems
- Containerized applications
- Kubernetes deployments
- Any environment where downstream dependencies may become unavailable