BeginnerPython~15 min

Getting Started with Rate Limiting

Prerequisites

Step 1: Start Valkey

docker run -d --name valkey -p 6379:6379 valkey/valkey:latest

Verify it's running:

docker exec valkey valkey-cli ping
# PONG

Step 2: Install Dependencies

pip install valkey

That's it - no special libraries needed. The redis Python package works with Valkey out of the box.

Step 3: Your First Rate Limiter

import valkey
import time

client = valkey.Valkey(host="localhost", port=6379, decode_responses=True)

def check_rate_limit(user_id: str, max_requests: int = 10, window: int = 60) -> dict:
    """Fixed-window rate limiter."""
    window_num = int(time.time() // window)
    key = f"rl:{user_id}:{window_num}"

    pipe = client.pipeline(transaction=True)
    pipe.incr(key)
    pipe.expire(key, window)
    results = pipe.execute()

    current = results[0]
    allowed = current <= max_requests

    return {
        "allowed": allowed,
        "current": current,
        "limit": max_requests,
        "remaining": max(0, max_requests - current),
    }

Step 4: Test It

# Send 12 requests - last 2 should be denied
for i in range(12):
    result = check_rate_limit("user-123", max_requests=10)
    status = "✅" if result["allowed"] else "❌"
    print(f"{status} Request {i+1}: {result['current']}/{result['limit']}")

Output:

✅ Request 1: 1/10
✅ Request 2: 2/10
...
✅ Request 10: 10/10
❌ Request 11: 11/10
❌ Request 12: 12/10

How It Works

Under the hood: We use INCR + EXPIRE in a pipeline. The key includes the window number (current timestamp ÷ window size), so it auto-rotates every window. Valkey handles all the atomic counting - no race conditions.

Operation Valkey Command Time
Increment counter INCR ~0.1ms
Set expiry EXPIRE ~0.1ms
Pipeline (both) 1 round-trip ~0.2ms total
Next → 02 - Token-Aware Limiting