Production-grade rate limiting, retry, and circuit breaking library
Project description
APIGuard
Production-grade rate limiting, retry, and circuit breaking library for Python.
Features
- Token Bucket Rate Limiting: Thread-safe rate limiting with configurable tokens and refill rate
- Retry with Backoff: Exponential backoff with jitter and Retry-After header support
- Circuit Breaker: Protects against cascading failures with CLOSED/OPEN/HALF_OPEN states
- Async Support: First-class async/await support via httpx adapter
- Registry: Per-user/per-resource rate limit tracking
- Structured Logging: JSON-structured log events for observability
Installation
pip install GRID-APIGUARD
Quick Start
Basic Rate Limiting
from apiguard import TokenBucket
bucket = TokenBucket(capacity=100, refill_rate=10.0)
if bucket.acquire(tokens=5):
# Make API call
pass
else:
# Wait or reject request
pass
Circuit Breaker
from apiguard import CircuitBreaker, CircuitOpenError
breaker = CircuitBreaker(
failure_threshold=5,
recovery_timeout=60.0,
)
try:
with breaker:
result = make_api_call()
except CircuitOpenError:
# Circuit is open, fail fast
handle_failure()
Retry Handler
from apiguard import RetryHandler, RetryExhaustedError
import httpx
retry = RetryHandler(
max_retries=3,
base_delay=1.0,
max_delay=60.0,
retryable_status_codes={429, 500, 502, 503, 504},
)
async def fetch_with_retry(url: str) -> httpx.Response:
async for attempt in retry.attempts():
response = await httpx.get(url)
if response.status_code in retry.retryable_status_codes:
retry.apply_backoff(attempt, response)
continue
return response
raise RetryExhaustedError("All retries exhausted")
RateLimitedClient (Composition)
from apiguard import RateLimitedClient, TokenBucket, RetryHandler, CircuitBreaker
client = RateLimitedClient(
bucket=TokenBucket(capacity=100, refill_rate=10.0),
retry=RetryHandler(max_retries=3),
breaker=CircuitBreaker(failure_threshold=5),
)
# Use as context manager
with client:
response = client.request("GET", "https://api.example.com/data")
Per-User Rate Limiting with Registry
from apiguard import BucketRegistry
registry = BucketRegistry(default_capacity=100, default_refill_rate=10.0)
# Get or create bucket for specific user
user_bucket = registry.get_bucket("user-123")
Async HTTP Client
from apiguard.adapters.httpx import AsyncRateLimitedClient
async with AsyncRateLimitedClient(
bucket=TokenBucket(capacity=100, refill_rate=10.0),
) as client:
response = await client.get("https://api.example.com/data")
API Reference
TokenBucket
TokenBucket(capacity: int, refill_rate: float)- Create a bucket with capacity tokens, refilling atrefill_ratetokens/secondacquire(tokens: int = 1) -> bool- Try to acquire tokens, returns True if successfulavailable() -> float- Current token count__enter__/__exit__- Context manager support (no-op, for composition)
CircuitBreaker
CircuitBreaker(failure_threshold: int, recovery_timeout: float, success_threshold: int = 1)- Configure breaker- States:
CLOSED,OPEN,HALF_OPEN __enter__- RaisesCircuitOpenErrorif circuit is OPEN__exit__(exc_type, exc_val, exc_tb)- Records success/failure and updates state
RetryHandler
RetryHandler(max_retries: int, base_delay: float = 1.0, max_delay: float = 60.0, jitter: float = 0.1, retryable_status_codes: set[int] | None = None)attempts() -> AsyncIterator[int]- Async generator yielding attempt numbersapply_backoff(attempt: int, response: httpx.Response | None = None) -> float- Apply backoff with optional Retry-After header
RateLimitedClient
RateLimitedClient(bucket: TokenBucket, retry: RetryHandler | None = None, breaker: CircuitBreaker | None = None)- Composes rate limiting, retry, and circuit breaking
- Thread-safe and reusable
BucketRegistry
BucketRegistry(default_capacity: int, default_refill_rate: float)get_bucket(key: str) -> TokenBucket- Get or create bucket for keyremove_bucket(key: str) -> bool- Remove bucket for key
Exceptions
CircuitOpenError- Raised when circuit is OPENRetryExhaustedError- Raised when all retries are exhausted
Development
Setup
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Testing
pytest # run all 60 tests
pytest --cov=apiguard # with coverage
pytest tests/test_bucket.py # single module
Linting & Type Checking
ruff check . # lint
ruff format . # format
mypy apiguard # strict type checking
Project Layout
apiguard/
bucket.py Token bucket rate limiter (thread-safe)
circuit.py Circuit breaker (CLOSED → OPEN → HALF_OPEN)
client.py Composed client (bucket + retry + breaker)
retry.py Exponential backoff with jitter & Retry-After
registry.py Per-key bucket registry
exceptions.py CircuitOpenError, RetryExhaustedError
logging.py Structured JSON log events
adapters/
httpx.py Async httpx integration
tests/ Mirrors apiguard/ — one test file per module
Requires Python ≥ 3.11. Build system: Hatchling.
License
MIT
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
grid_apiguard-0.1.0.tar.gz
(17.3 kB
view details)
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 grid_apiguard-0.1.0.tar.gz.
File metadata
- Download URL: grid_apiguard-0.1.0.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
618c46a7c6672916c61bd1dd23c7fe3596d4b346893db6b2c71cb2a6c4572967
|
|
| MD5 |
7b17e0c6124d0d095abb1bae3b61ff92
|
|
| BLAKE2b-256 |
0552bc7088b657b8160af8dd333ee749895188398af2fcfba4ee69cc36f5e25e
|
File details
Details for the file grid_apiguard-0.1.0-py3-none-any.whl.
File metadata
- Download URL: grid_apiguard-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49f8e3a35796ce82edb6eaa307ffca9e0b6e27958987c1d7c41a892e32bd0d71
|
|
| MD5 |
4f82ec53c44d4edee36c71e8a89bae3b
|
|
| BLAKE2b-256 |
99db7f0857f328c212216b906339f7b144105f7fef88e8022ab53deec8d31719
|