Skip to main content

A production-grade distributed rate limiter package using Redis and FastAPI, featuring Sliding Window and Token Bucket strategies.

Project description

throttlecore

License: MIT Python Version FastAPI Support

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, throttlecore defaults 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 fakeredis so 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

throttlecore-0.1.0.tar.gz (22.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

throttlecore-0.1.0-py3-none-any.whl (23.8 kB view details)

Uploaded Python 3

File details

Details for the file throttlecore-0.1.0.tar.gz.

File metadata

  • Download URL: throttlecore-0.1.0.tar.gz
  • Upload date:
  • Size: 22.9 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for throttlecore-0.1.0.tar.gz
Algorithm Hash digest
SHA256 98b85959560f2dbf2d1865cf1039bc98ce3be2d911a1975b27c073567a58a21f
MD5 118fd41ba9b83255e72fd343ef4a795c
BLAKE2b-256 64755b7cc0a392fb5d2f960b7ab949d427fcd7fc2dffa9403b2a19c3148f6e7f

See more details on using hashes here.

File details

Details for the file throttlecore-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: throttlecore-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.8 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for throttlecore-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 91fb3e30c261cf4ce19d3cbe88ece8e2c66e3fb339d6a75eacaf270cbe1c2b95
MD5 34a911103a03d767fb6b6c4dd9a78c22
BLAKE2b-256 a694d13c9000c1ad7740f045d58d40bd5a6ebd8a8035ec8f13db187c1c778762

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page