throttlecore
A production-grade, highly resilient distributed rate limiting package for Python applications utilizing Redis.
throttlecore implements atomic evaluation strategies using single-threaded Redis Lua scripts to eliminate network round-trips and race conditions in multi-node environments.
🌟 Features
- 🚀 Atomic Operations: All logic executes inside Redis memory, eliminating race conditions.
- ⚙️ Pluggable Strategies: Supports both Sliding Window Log (eliminating edge-of-window bursts) and Token Bucket (handling bursts with smooth refills).
- 🔒 FastAPI Native: Comes with first-class decorator and dependency injection support.
- 🛡️ Operational Resilience (Fail-Open): If your central Redis cluster goes offline,
throttlecoredefaults to a fail-open policy to keep your app responsive, warning operators without blocking users. - 📊 Simulation Dashboard: Includes a premium, responsive glassmorphic web dashboard to visually inspect window sliding, token refilling, and throughput graphs in real time.
- 🧪 Zero-Config Local Testing: Out-of-the-box support for
fakeredisso you can write tests and run the simulator without starting a real Redis instance.
🏗️ Architecture
sequenceDiagram
participant Client
participant FastAPI Node A
participant FastAPI Node B
participant Redis (Atomic Engine)
Client->>FastAPI Node A: Request /api/data (X-API-Key: key123)
Note over FastAPI Node A: Executes throttlecore middleware
FastAPI Node A->>Redis: EVALSHA Sliding Window Script (key123)
Note over Redis: Drops logs older than (Now - Window)<br/>Counts current logs in ZSET<br/>Admit request & updates TTL if under limit
Redis-->>FastAPI Node A: [Allowed: true, Remaining: 4, RetryAfter: 0]
FastAPI Node A-->>Client: HTTP 200 OK (Allowed)
Client->>FastAPI Node B: Concurrent Request /api/data (X-API-Key: key123)
FastAPI Node B->>Redis: EVALSHA Sliding Window Script (key123)
Note over Redis: Log limit exceeded
Redis-->>FastAPI Node B: [Allowed: false, Remaining: 0, RetryAfter: 4.85]
FastAPI Node B-->>Client: HTTP 429 Too Many Requests (Retry-After: 5)
📦 Installation
To install throttlecore with core dependencies:
pip install redis fastapi
To install with development and simulation dashboard dependencies (including fakeredis and uvicorn):
pip install "throttlecore[dev]"
# Or locally
pip install -e .[dev]
🚀 Quick Start
1. Basic Python Usage
import asyncio
import redis.asyncio as aioredis
from throttlecore import DistributedRateLimiter, TokenBucketStrategy, RateLimitExceeded
async def main():
# 1. Initialize Redis Client
redis_client = aioredis.from_url("redis://localhost:6379/0", decode_responses=True)
# 2. Initialize Rate Limiter (Defaults to Sliding Window Log Strategy)
limiter = DistributedRateLimiter(
redis_client=redis_client,
default_strategy=TokenBucketStrategy(), # Switch strategies easily
fail_open=True # Fail-open if Redis goes offline
)
# 3. Check and assert limits
try:
# Allow 5 requests per 10 seconds
await limiter.is_allowed(key="user_12345", limit=5, window_seconds=10)
print("Request allowed!")
except RateLimitExceeded as e:
print(f"Blocked! Try again in {e.retry_after:.2f} seconds.")
await redis_client.aclose()
asyncio.run(main())
2. Integration with FastAPI
Inject rate limiting directly into path operations or globally using standard FastAPI dependencies:
from fastapi import FastAPI, Depends
import redis.asyncio as aioredis
from throttlecore import DistributedRateLimiter, RateLimitDecorator, TokenBucketStrategy
app = FastAPI()
redis_client = aioredis.from_url("redis://localhost:6379/0", decode_responses=True)
limiter = DistributedRateLimiter(redis_client)
# Define a route limited to 5 requests per 10 seconds (Sliding Window Log)
@app.get("/items", dependencies=[Depends(RateLimitDecorator(limiter, limit=5, window=10))])
async def read_items():
return [{"item_id": "Foo"}, {"item_id": "Bar"}]
# Define a route limited using Token Bucket Strategy and consuming 2 tokens per request
@app.get("/heavy-job", dependencies=[
Depends(RateLimitDecorator(
limiter=limiter,
limit=10,
window=60,
cost=2,
strategy=TokenBucketStrategy()
))
])
async def run_heavy_job():
return {"status": "processing"}
📊 Live Simulation Dashboard
throttlecore comes bundled with a beautiful visual simulator. It runs on fakeredis by default if no running Redis instance is detected on localhost:6379, so it works instantly.
To run the simulator:
python -m throttlecore.dashboard.app
Then navigate to http://localhost:8000.
Dashboard Visualizations:
- Sliding Window Log Timeline: Watch request timestamps sliding along a timeline in real-time, falling off the window boundary as time moves forward.
- Token Bucket Liquid Gauge: A dynamic container displaying the fluid level (current token count) refilling smoothly between request bursts.
- Live Charts: Charts plotting accepted and blocked throughput per second.
- Redis DB Inspector: Live JSON display showing what is stored in Redis (ZSET records or Hash fields) at any millisecond.
🧪 Testing
We use pytest with pytest-asyncio and fakeredis[lua] to validate all components, concurrency race conditions, and algorithm variations.
# Run the test suite
pytest tests/ -v
🛡️ License
Distributed under the MIT License. See LICENSE for details.
Release files for throttlecore 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| throttlecore-0.1.0.tar.gz | 22.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| throttlecore-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 46.7 kB
Release files / throttlecore-0.1.0.tar.gz
| Download URL | throttlecore-0.1.0.tar.gz |
|---|---|
| Size | 22.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
98b85959560f2dbf2d1865cf1039bc98ce3be2d911a1975b27c073567a58a21f
|
|
BLAKE2b-256 checksum How to use checksums |
64755b7cc0a392fb5d2f960b7ab949d427fcd7fc2dffa9403b2a19c3148f6e7f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / throttlecore-0.1.0-py3-none-any.whl
| Download URL | throttlecore-0.1.0-py3-none-any.whl |
|---|---|
| Size | 23.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
91fb3e30c261cf4ce19d3cbe88ece8e2c66e3fb339d6a75eacaf270cbe1c2b95
|
|
BLAKE2b-256 checksum How to use checksums |
a694d13c9000c1ad7740f045d58d40bd5a6ebd8a8035ec8f13db187c1c778762
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|