Lightweight, thread-safe rate limiting for Python — token bucket, sliding window, fixed window, leaky bucket
Project description
fluxcontrol
Lightweight, thread-safe rate limiting for Python
Zero dependencies. Four algorithms. One API.
Why fluxcontrol?
Rate limiting is a fundamental building block of distributed systems — yet the Python ecosystem forces developers to choose between bloated frameworks and single-algorithm libraries.
- slowapi bundles Flask/Starlette dependencies and only implements fixed-window counters.
- ratelimit provides a single decorator with one algorithm and no per-key support.
- limits (the library behind flask-limiter) is well-designed but pulls in storage backend dependencies and is tightly coupled to web frameworks.
- flask-limiter only works with Flask and delegates to
limits.
fluxcontrol fills a gap that no existing package addresses: a single, dependency-free library that provides four production-proven rate-limiting algorithms through a unified API — usable as a decorator, context manager, or manual guard, without any framework lock-in.
Quick Start
pip install fluxcontrol
from fluxcontrol import RateLimiter
# Decorator
@RateLimiter(calls=10, period=60)
def api_call():
return do_work()
# Manual check
limiter = RateLimiter(calls=100, period=60)
if limiter.allow("user_123"):
process_request()
# Context manager
with limiter.acquire("user_123", timeout=5):
call_external_api()
Use Cases
| Use Case | Recommended Algorithm | Why |
|---|---|---|
| API Rate Limiting | Token Bucket | Allows legitimate bursts while enforcing sustained rate |
| DDoS Protection | Sliding Window | Precise control with no boundary-exploitable windows |
| Resource Throttling | Leaky Bucket | Smooths output to a fixed rate, prevents resource spikes |
| Queue Management | Leaky Bucket | Models queue drain rate naturally |
| Per-User Limits | Any (with key_func) | key_func routes each user to an independent bucket |
| Billing Enforcement | Sliding Window | Accurate accounting across window boundaries |
| Simple Capping | Fixed Window | Minimal overhead when precision isn't critical |
Algorithm Comparison
Choosing the right algorithm depends on your traffic pattern and precision requirements:
Token Bucket
The workhorse of rate limiting. Tokens are added at a fixed rate and consumed per request. Accumulated tokens allow bursts up to the bucket capacity, then requests are rejected until tokens refill.
When to use: APIs with variable traffic, user-facing services that need burst tolerance, any scenario where you want to be "generous but bounded."
Sliding Window
Tracks request timestamps in a rolling window. Unlike fixed windows, there are no boundary artifacts — a window starting at 12:59 and one at 13:00 are part of the same continuous time span.
When to use: Billing or quota enforcement where precision matters, compliance-sensitive rate limits, preventing window-boundary attacks.
Fixed Window
Divides time into discrete buckets (e.g., 60-second windows starting at :00 seconds). Counts requests per bucket. Simple, fast, but susceptible to boundary bursts — two requests at 12:59:59 and 13:00:01 each land in different windows.
When to use: Prototyping, internal services where approximate limits suffice, high-throughput scenarios where minimal overhead is critical.
Leaky Bucket
Models a queue with a fixed drain rate. Requests enter a queue; the queue drains at a constant rate regardless of inflow. This smooths traffic rather than rejecting bursts.
When to use: Output to external APIs with strict rate limits, database write throttling, any downstream system that can't handle bursty input.
Token Bucket Leaky Bucket
┌──────────┐ ┌──────────┐
Tokens │ ▓▓▓▓░░░░ │ Requests │ ▓▓▓░░░░░ │ Queue
refill → │ │ ──────────→ │ │ ──→ drain
at rate │ capacity │ │ capacity │ at rate
└──────────┘ └──────────┘
Allows bursts Smooths output
Features
- 🧵 Thread-safe by default — all algorithms use internal locking
- 🔑 Per-key limiting — per user, IP, API key, or any custom key function
- 🎯 Three usage modes — decorator, context manager, manual guard
- 📊 Stats & monitoring — built-in usage statistics per key
- ⏱️ Retry-After — standard HTTP
Retry-Afterheader values out of the box - 🚫 Zero dependencies — pure Python, no framework coupling
- 📦 Four algorithms — token bucket, sliding window, fixed window, leaky bucket
Comparison with Existing Solutions
| Feature | fluxcontrol | slowapi | ratelimit | limits | flask-limiter |
|---|---|---|---|---|---|
| Token Bucket | ✅ | ❌ | ❌ | ✅ | ✅ |
| Sliding Window | ✅ | ❌ | ❌ | ✅ | ✅ |
| Fixed Window | ✅ | ✅ | ✅ | ✅ | ✅ |
| Leaky Bucket | ✅ | ❌ | ❌ | ✅ | ❌ |
| Zero Dependencies | ✅ | ❌ | ✅ | ❌ | ❌ |
| Per-Key Limiting | ✅ | ✅ | ❌ | ✅ | ✅ |
| Context Manager | ✅ | ❌ | ❌ | ❌ | ❌ |
| Built-in Stats | ✅ | ❌ | ❌ | ❌ | ✅ |
| Framework Agnostic | ✅ | ❌ | ✅ | ✅ | ❌ |
| Thread-Safe | ✅ | ✅ | ❌ | ✅ | ✅ |
Design Philosophy
-
Unified API, Multiple Strategies — one
RateLimiterclass, four algorithms. Switch strategies by changing a string argument — no rewrites, no adapter pattern ceremony. -
Zero-Dependency by Default — no Redis, no Flask, no Celery. Import and go. Add storage backends only when you need distributed coordination.
-
Framework Agnostic — fluxcontrol doesn't know or care whether you're building a Flask API, a FastAPI service, a CLI tool, or a background worker. Rate limiting is orthogonal to your framework choice.
-
Safety First — every public method is thread-safe. No footguns.
RateLimitExceededexceptions carryretry_aftervalues so you can build compliant HTTP responses without extra math. -
Progressive Complexity — start with
@RateLimiter(calls=100, period=60). Add per-key limiting. Switch algorithms. Plug in custom key functions. Each layer of complexity is opt-in.
API Reference
RateLimiter(calls, period, algorithm="token_bucket", ...)
High-level API supporting all four algorithms.
RateLimiter(
calls=100, # max calls per period
period=60, # time window in seconds
algorithm="token_bucket", # "token_bucket", "sliding_window", "fixed_window", "leaky_bucket"
key_func=lambda user: user, # per-key rate limiting
burst=150, # burst capacity (token bucket)
raise_on_limit=True, # raise exception or return None
)
Low-Level APIs
from fluxcontrol import TokenBucket, SlidingWindow, FixedWindow, LeakyBucket
# Token Bucket — allows bursts up to capacity
tb = TokenBucket(rate=10, capacity=50)
tb.allow() # consume 1 token
tb.consume(5) # consume 5 tokens
tb.retry_after() # seconds until next available
tb.available # current token count
tb.stats() # usage statistics
# Sliding Window — precise, no boundary burst
sw = SlidingWindow(max_calls=100, window_seconds=60)
sw.allow("user_id")
sw.count # calls in current window
sw.retry_after("user_id")
# Fixed Window — simple, fast
fw = FixedWindow(max_calls=100, window_seconds=60)
fw.allow("user_id")
# Leaky Bucket — smooth output rate
lb = LeakyBucket(rate=10, capacity=50)
lb.allow("user_id")
lb.level # current queue level
Exceptions
from fluxcontrol.exceptions import RateLimitExceeded, TimeoutExceeded
try:
rate_limited_func()
except RateLimitExceeded as e:
retry_after = e.retry_after # seconds to wait
License
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
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 fluxrate-0.3.0.tar.gz.
File metadata
- Download URL: fluxrate-0.3.0.tar.gz
- Upload date:
- Size: 15.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7036ada091eb1dce6ded3c0b45557918e53b62521355c0e973dd598df37acd77
|
|
| MD5 |
8fcd67ff18e6013904a87d98766f7a62
|
|
| BLAKE2b-256 |
eb6a379826f175e2e1c38ac1db54d02f3ec0ee98b00bb6307d1f583c81f3ae44
|
File details
Details for the file fluxrate-0.3.0-py3-none-any.whl.
File metadata
- Download URL: fluxrate-0.3.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a894f04c6aa2d8eb5c3f16435c213e76475d31cf7f7da5a816847ce294d36220
|
|
| MD5 |
3f7b85fc4a2f27d610c89355ee7993ad
|
|
| BLAKE2b-256 |
c74411af5b0ed055a3246c84385d148b873c8333d5f1b4a73cfb4c325dff6e04
|