Skip to main content

In-memory rate limiter with sliding window, token bucket, and leaky bucket algorithms.

Project description

philiprehberger-rate-limiter

Tests PyPI version Last updated

In-memory rate limiter with sliding window, token bucket, and leaky bucket algorithms.

Installation

pip install philiprehberger-rate-limiter

Usage

from philiprehberger_rate_limiter import RateLimiter, Algorithm

limiter = RateLimiter(
    requests=100,
    window_seconds=60,
    algorithm=Algorithm.SLIDING_WINDOW,
)

if limiter.allow("user-123"):
    handle_request()

Check Status

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
status = limiter.status("user-123")
print(f"Allowed: {status.allowed}")
print(f"Remaining: {status.remaining}/{status.limit}")
print(f"Resets at: {status.reset_at}")

Usage Statistics

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
limiter.allow("user-123")

stats = limiter.get_stats("user-123")
print(f"Current usage: {stats.current_usage}")
print(f"Remaining: {stats.remaining}")
print(f"Reset at: {stats.reset_at}")

Format status

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)
for _ in range(15):
    limiter.allow("user:123")

print(limiter.format_status("user:123"))
# "15/100 requests used (85 remaining); resets in 23.5s"

Blocking Wait

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)

# Synchronous — blocks until quota is available or timeout expires
status = limiter.wait("user-123", timeout=5.0)

# Async — awaits until quota is available
status = await limiter.async_acquire("user-123")

Async Context Manager

from philiprehberger_rate_limiter import RateLimiter

limiter = RateLimiter(100, 60)

async with limiter:
    status = await limiter.async_acquire("user-123")
    if status.allowed:
        await handle_request()

Decorator

from philiprehberger_rate_limiter import RateLimiter, rate_limit

# Standalone decorator
@rate_limit(calls=10, period=60)
def api_endpoint():
    return {"data": "ok"}

# Instance-based decorator
limiter = RateLimiter(10, 60)

@limiter.limit("10/minute")
def another_endpoint():
    return {"data": "ok"}

# Async function decorator
@rate_limit(calls=10, period=60)
async def async_endpoint():
    return {"data": "ok"}

Rate Limiter Groups

from philiprehberger_rate_limiter import RateLimiter, RateLimiterGroup

limiter = RateLimiter(100, 60)
group = RateLimiterGroup(limiter, ["api-key-1", "api-key-2", "api-key-3"])

# All keys in the group share one rate limit pool
group.allow("api-key-1")  # consumes from shared pool
group.allow("api-key-2")  # consumes from same pool

stats = group.get_stats()
print(f"Group usage: {stats.current_usage}/{stats.limit}")

Algorithms

from philiprehberger_rate_limiter import RateLimiter, Algorithm

# Fixed window — resets at interval boundaries
RateLimiter(100, 60, Algorithm.FIXED_WINDOW)

# Sliding window (default) — rolling time window
RateLimiter(100, 60, Algorithm.SLIDING_WINDOW)

# Token bucket — smooth rate with burst capacity
RateLimiter(100, 60, Algorithm.TOKEN_BUCKET)

# Leaky bucket — constant drain rate, smooths bursts
RateLimiter(100, 60, Algorithm.LEAKY_BUCKET)

API

Function / Class Description
RateLimiter(requests, window_seconds, algorithm) Create a rate limiter
limiter.allow(key) Check if request is allowed
limiter.status(key) Get detailed LimitStatus
limiter.get_stats(key) Get RateLimiterStats without consuming a request
limiter.format_status(key) Get a human-readable single-line summary (e.g. "15/100 requests used (85 remaining); resets in 23.5s")
limiter.wait(key, timeout) Block until quota available or raise RateLimitExceeded
limiter.async_acquire(key) Async wait until quota is available
limiter.reset(key) Reset state for a key
limiter.reset_all() Reset state for all keys
limiter.active_keys() List all keys with active state
limiter.limit(rate) Decorator with rate string (e.g., "10/minute")
RateLimiterGroup(limiter, keys) Create a shared rate limit group
group.allow(key) Check if request is allowed against shared pool
group.status(key) Get shared LimitStatus
group.get_stats() Get shared RateLimiterStats
group.reset() Reset shared group state
rate_limit(calls, period, algorithm) Standalone decorator for rate limiting
format_status(status) Format a LimitStatus as a human-readable summary string
Algorithm Enum: FIXED_WINDOW, SLIDING_WINDOW, TOKEN_BUCKET, LEAKY_BUCKET
LimitStatus Dataclass: allowed, remaining, reset_at, limit
RateLimiterStats Dataclass: current_usage, remaining, reset_at, limit
RateLimitExceeded Exception raised when rate limit is exceeded

Development

pip install -e .
python -m pytest tests/ -v

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

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

philiprehberger_rate_limiter-0.5.0.tar.gz (11.7 kB view details)

Uploaded Source

Built Distribution

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

philiprehberger_rate_limiter-0.5.0-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file philiprehberger_rate_limiter-0.5.0.tar.gz.

File metadata

File hashes

Hashes for philiprehberger_rate_limiter-0.5.0.tar.gz
Algorithm Hash digest
SHA256 4596ba6a3e09d81299089c7ef4a1d58a35bf218de8495f2f41e383c61a8cf1ca
MD5 db51e4c55c8b1a289daf0784ee25777a
BLAKE2b-256 e1d71d04544345b5eade8e02f7e0193e3d55b680295a42ae6e27433853a24677

See more details on using hashes here.

File details

Details for the file philiprehberger_rate_limiter-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for philiprehberger_rate_limiter-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aadf7b396fc8e807cc6bac5a2d5f08e89c639ba10574675df617c3fba048f42c
MD5 b5c115d5a80096e99e03f7eff9f4f2a3
BLAKE2b-256 52c2bb09310d6897618fe106e426fb0feef23368faf2ef10c06369ef43e423d6

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