CentralizedRateLimiter
A robust, centralized rate limiting utility for Python applications that need precise control over API request rates with built-in retry mechanisms and support for multiple rate limits.
🔧 Installation
pip install centralized-rate-limiter
🌟 Features
- Multiple Rate Limits: Support for multiple concurrent rate limits (e.g., per-second, per-minute, per-hour)
- Centralized Configuration: Set rate limiting parameters once and reuse across your application for all request methods
- Comprehensive Retry Logic: Built-in exponential backoff and configurable retry attempts
- Thread-Safe: Reliable rate limiting in multi-threaded environments
- Flexible HTTP Support: Works with all standard HTTP methods
- Session Management: Extends
requests.Sessionfor seamless integration - Type Hints: Full type annotation support for better IDE integration
🎯 Quick Start
from centralized_rate_limiter import get_rate_limiter
# Create a rate limiter with single rate limit (backward compatible)
rate_limiter = get_rate_limiter(
requests_per_second=10,
total_retries=5,
backoff_factor=0.25
)
# Create a rate limiter with multiple rate limits
rate_limiter = get_rate_limiter(
requests_per_second=10, # Base rate: 10 requests per second
additional_limits=[
(60, 60), # 60 requests per minute
(2000, 3600) # 2000 requests per hour
],
total_retries=5,
backoff_factor=0.25
)
# Use it for your API calls
response = rate_limiter.get('https://api.example.com/data')
# Works with all HTTP methods
post_response = rate_limiter.post(
'https://api.example.com/create',
json={'key': 'value'}
)
🔧 Advanced Usage
Custom Configuration
from centralized_rate_limiter import RateLimitedSession
# Create a session with multiple rate limits
session = RateLimitedSession(
requests_per_second=5,
additional_limits=[
(100, 60), # 100 requests per minute
(2000, 3600) # 2000 requests per hour
],
total_retries=3,
backoff_factor=0.5
)
# Use session in your application
responses = []
for endpoint in endpoints:
response = session.get(endpoint)
responses.append(response)
Error Handling
from requests.exceptions import RetryError
try:
response = rate_limiter.get('https://api.example.com/data')
data = response.json()
except RetryError:
print("Max retries exceeded")
except Exception as e:
print(f"An error occurred: {e}")
📊 Configuration Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
requests_per_second |
int | 10 | Maximum number of requests allowed per second |
additional_limits |
List[Tuple[int, float]] | None | Additional rate limits as (max_calls, period) tuples |
total_retries |
int | 5 | Maximum number of retry attempts for failed requests |
backoff_factor |
float | 0.25 | Multiplier for exponential backoff between retries |
Additional Limits Format
The additional_limits parameter accepts a list of tuples, where each tuple contains:
- First element: Maximum number of calls allowed in the period
- Second element: Period in seconds
Example:
additional_limits=[
(60, 60), # 60 calls per 60 seconds (per minute)
(2000, 3600) # 2000 calls per 3600 seconds (per hour)
]
🤔 When to Use This vs. Other Solutions
Use CentralizedRateLimiter When You Need:
-
Multiple Rate Limits
- You need to handle multiple concurrent rate limits (e.g., per-second, per-minute, per-hour)
- You want to enforce different rate limits for different time windows
- You need to comply with complex API rate limit requirements
-
Centralized Rate Limiting and Retry Logic
- You want a single solution that handles both rate limiting and retries
- You want a single rate limit for all your requests methods
- You need fine-grained control over retry behavior
-
Thread-Safe Operation
- Your application makes API calls from multiple threads
- You need reliable rate limiting in concurrent scenarios
-
Session Management
- You want to maintain session state across requests
- You need to reuse connections for better performance
Consider Alternatives When:
-
Distributed Rate Limiting Required
- Consider
python-redis-rate-limitfor distributed systems - Use
Flask-Limiterfor API endpoint protection
- Consider
-
Simpler Requirements
- Use
requests-ratelimiterfor basic rate limiting - Use
backoffpackage for simple retry logic
- Use
-
Async Operation
- Consider
aiohttpwithaiohttp-client-manager - Use
asynciobased solutions for async workflows
- Consider
🔍 How It Works
The library uses a combination of:
- Thread-safe rate limiting for multiple concurrent limits
- Decorator-based rate limiting using the
ratelimitpackage urllib3.util.Retryfor configurable retry behavior- Custom session management extending
requests.Session
Example retry sequence:
Request 1 (fails) → Wait 0.25s → Retry 1 (fails) → Wait 0.5s → Retry 2 (succeeds)
Example with multiple rate limits:
# Configuration
limits = [
(60, 60), # 60 requests per minute
(2000, 3600) # 2000 requests per hour
]
# The rate limiter will ensure all limits are respected:
# - No more than 60 requests in any 60-second window
# - No more than 2000 requests in any 3600-second (1 hour) window
🛠️ Development
Prerequisites
- Python 3.7+
- Make (optional, but recommended)
- Git
Setting Up Development Environment
- Clone the repository:
git clone https://github.com/waddafunk/CentralizedRateLimiter.git
cd CentralizedRateLimiter
- Install development dependencies:
make dev-install
Or without make:
python -m pip install -e ".[dev]"
Development Tools
The project uses several development tools, all configured in pyproject.toml:
Code Formatting
- Black: Code formatter with a line length of 88 characters
- isort: Import statement organizer, configured to work with Black
- pyupgrade: Automatically upgrades Python syntax for newer versions
# Format all code
make format
or without make
# Individual tools
python -m black .
python -m isort .
python -m pyupgrade --py37-plus **/*.py
Code Quality
- pylint: Static code analysis
- flake8: Style guide enforcement
# Run all linters
make lint
or without make
python -m pylint centralized_rate_limiter tests
python -m flake8 centralized_rate_limiter tests
Testing
- pytest: Test framework
- pytest-cov: Coverage reporting
- responses: HTTP request mocking
# Run tests with coverage
make test
or without make
make coverage
Development Workflow
- Create a new branch for your feature:
git checkout -b feature/your-feature-name
- Make your changes and ensure quality:
make format # Format code
make lint # Check code quality
make test # Run tests
# Or run all checks at once:
make all
- Build and check the package:
make build
- Submit a pull request
Available Make Commands
| Command | Description |
|---|---|
make install |
Install package for production |
make dev-install |
Install package with development dependencies |
make format |
Format code using black and isort |
make lint |
Run code quality checks |
make test |
Run tests with pytest |
make coverage |
Generate test coverage report |
make clean |
Remove build artifacts and cache files |
make build |
Build distribution packages |
make publish |
Prepare package for PyPI publishing |
make all |
Run all quality checks and tests |
make help |
Show available commands |
Project Structure
centralized_rate_limiter/
├── .git/
├── .gitignore
├── centralized_rate_limiter/
│ ├── __init__.py
│ └── rate_limiting.py
├── tests/
│ └── test_rate_limiting.py
├── Makefile
├── pyproject.toml
├── README.md
└── LICENSE
Configuration Files
pyproject.toml
The pyproject.toml file contains all project configurations:
- Build system configuration
- Package metadata
- Dependencies (both runtime and development)
- Tool configurations:
- pytest settings
- coverage settings
- black configuration
- isort configuration
Makefile
The Makefile provides convenient commands for common development tasks. See the commands table above for available operations.
Continuous Integration
The project uses GitHub Actions for CI/CD, running the following checks on each pull request:
- Code formatting (black, isort)
- Linting (pylint, flake8)
- Tests with coverage reporting
- Package building
🤝 Contributing
Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
📜 License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
📚 API Reference
RateLimitedSession
class RateLimitedSession(requests.Session):
"""A rate-limited HTTP session with built-in retry logic."""
def __init__(
self,
requests_per_second: int = 10,
total_retries: int = 5,
backoff_factor: float = 0.25,
additional_limits: Optional[List[Tuple[int, float]]] = None
) -> None:
"""Initialize a new rate-limited session."""
get_rate_limiter
def get_rate_limiter(
requests_per_second: int = 10,
total_retries: int = 5,
backoff_factor: float = 0.25,
additional_limits: Optional[List[Tuple[int, float]]] = None
) -> RateLimitedSession:
"""Create a new rate-limited session with specified parameters."""
🙏 Acknowledgments
📧 Contact
For questions and support, please open an issue in the GitHub repository.
Made with ❤️ for the Python community
Metadata
Release files for centralized-rate-limiter 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| centralized_rate_limiter-0.2.2.tar.gz | 13.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| centralized_rate_limiter-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.4 kB
Release files / centralized_rate_limiter-0.2.2.tar.gz
| Download URL | centralized_rate_limiter-0.2.2.tar.gz |
|---|---|
| Size | 13.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ff3b267ba0641a0e3b60cf77fb6734c0ee0c504f0aa3fbf005352da3cf7423c4
|
|
BLAKE2b-256 checksum How to use checksums |
d42409452b955b5e458ba13b9abe318837d9be092cd19ef0577b72e32d6eea8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.21
|
Release files / centralized_rate_limiter-0.2.2-py3-none-any.whl
| Download URL | centralized_rate_limiter-0.2.2-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a75f8ddeec6e1b3f0403874258dadefb1b26e5d60f61e4c9416293b6df1c6da
|
|
BLAKE2b-256 checksum How to use checksums |
03b69ca7cd2559523055dce38205a44d7efbece4475e821590e344d90d4894bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.9.21
|