Multi-Tenant Rate Limiting
Relevant source files
The following files were used as context for generating this wiki page:
- examples/multi_tenant.py
- tests/test_multi_tenant.py
- README.md
- examples/fastapi_app.py
- tests/test_decorators.py
- fastlimit/limiter.py (Inferred from project structure and usage in CONTRIBUTING.md)
Multi-tenant rate limiting in FastLimit allows developers to enforce isolated quotas for different users, organizations, or API keys within a single application. This feature is essential for SaaS platforms that provide tiered service levels (e.g., Free, Premium, Enterprise), ensuring that high-usage tenants do not exhaust resources intended for others.
The system uses a combination of unique keys and "tenant types" to partition the Redis-backed counters. This ensures that a request made by "Tenant A" under a "Free" tier does not affect the remaining quota for "Tenant B" or even "Tenant A" under a different service category.
Sources: README.md:15-20, examples/multi_tenant.py:7-12, tests/test_multi_tenant.py:16-20
Architecture and Core Logic
The multi-tenant system operates by extending the standard rate-limiting key with a tenant_type identifier. When a check is performed, the underlying Redis backend isolates counters based on the unique combination of the provided key and the tenant_type.
Key Components
| Component | Description |
|---|---|
key | A unique identifier for the specific tenant (e.g., User ID, Organization ID, or API Key). |
tenant_type | An optional string that defines the category or tier of the tenant (e.g., "premium", "free:analytics"). |
rate | The throughput limit defined as a string (e.g., "100/minute"). |
limiter.check() | The core async method used to verify if a tenant's request is within their allowed quota. |
Sources: examples/multi_tenant.py:108-112, README.md:204-214, CONTRIBUTING.md:286-300
Multi-Tenant Request Flow
The following diagram illustrates how a request is processed when multi-tenant rate limiting is applied, using a tier-based lookup.
Implementation Methods
FastLimit provides two primary ways to implement multi-tenant limiting: via the @limiter.limit decorator or through direct manual checks.
Decorator-Based Implementation
The decorator approach allows for declarative rate limiting where the key and tenant type are extracted dynamically from the incoming request object.
@app.get("/api/data")
@limiter.limit(
rate="100/hour",
key=lambda req: req.headers.get("X-API-Key"),
tenant_type=lambda req: get_user_tier(req.headers.get("X-API-Key"))
)
async def get_data(request: Request):
return {"data": "..."}
Sources: README.md:204-214, tests/test_decorators.py:49-60
Manual Check Implementation
For complex logic where the rate limit depends on runtime data, the limiter.check method can be called directly within the endpoint logic.
tenant_id, tier, name = get_tenant_info(x_api_key)
limit = TIER_LIMITS[tier]["data"]
await limiter.check(
key=tenant_id,
rate=limit,
tenant_type=tier
)
Sources: examples/multi_tenant.py:108-115, tests/test_multi_tenant.py:53-60
Tenant Isolation and Upgrades
Isolation Logic
FastLimit ensures strict isolation between different tenant_type values even for the same key. This is useful for "Upgrade" scenarios where a user might transition from a "free" tier to a "premium" tier. In such cases, the "premium" counter is initialized separately, and the "free" counter remains in its exhausted state until the window expires.
Sources: tests/test_multi_tenant.py:16-41, tests/test_multi_tenant.py:75-103
Resetting Tenant Quotas
Administrative actions, such as a subscription upgrade, may require resetting a tenant's usage. The limiter.reset() function supports an optional tenant_type parameter to target specific quotas.
- Specific Reset:
await limiter.reset(key="tenant-01", tenant_type="free")clears only the free tier quota. - Global Reset:
await limiter.reset(key="tenant-01")(without a tenant type) can be used to clear all quotas associated with that key if configured accordingly.
Sources: examples/multi_tenant.py:228-232, tests/test_multi_tenant.py:246-272
Usage Tracking and Visibility
Tenants can be provided with visibility into their current consumption using the get_usage method. This returns a dictionary containing the current count, the limit, and the remaining requests.
| Field | Description |
|---|---|
current | Number of requests made in the current window. |
limit | The maximum requests allowed (extracted from the rate string). |
remaining | limit - current. |
ttl | Seconds remaining until the current window resets. |
Sources: examples/multi_tenant.py:186-193, tests/test_multi_tenant.py:226-241
Conclusion
Multi-tenant rate limiting in FastLimit provides a robust framework for managing API consumption across diverse user bases. By leveraging Redis for atomic operations and providing flexible integration points through decorators and manual checks, it allows for sophisticated SaaS-style tiered limit enforcement with minimal performance overhead.
Sources: README.md:10-15, examples/multi_tenant.py:1-6