danswer/backend/onyx/server/middleware/rate_limiting.py
pablonyx 5b5c1166ca
Async Redis (#3618)
* k

* update configs for clarity

* typing

* update
2025-01-07 19:34:57 +00:00

49 lines
1.7 KiB
Python

from collections.abc import Callable
from typing import List
from fastapi import Depends
from fastapi import Request
from fastapi_limiter import FastAPILimiter
from fastapi_limiter.depends import RateLimiter
from onyx.configs.app_configs import AUTH_RATE_LIMITING_ENABLED
from onyx.configs.app_configs import RATE_LIMIT_MAX_REQUESTS
from onyx.configs.app_configs import RATE_LIMIT_WINDOW_SECONDS
from onyx.redis.redis_pool import get_async_redis_connection
async def setup_auth_limiter() -> None:
# Use the centralized async Redis connection
redis = await get_async_redis_connection()
await FastAPILimiter.init(redis)
async def close_auth_limiter() -> None:
# This closes the FastAPILimiter connection so we don't leave open connections to Redis.
await FastAPILimiter.close()
async def rate_limit_key(request: Request) -> str:
# Uses both IP and User-Agent to make collisions less likely if IP is behind NAT.
# If request.client is None, a fallback is used to avoid completely unknown keys.
# This helps ensure we have a unique key for each 'user' in simple scenarios.
ip_part = request.client.host if request.client else "unknown"
ua_part = request.headers.get("user-agent", "none").replace(" ", "_")
return f"{ip_part}-{ua_part}"
def get_auth_rate_limiters() -> List[Callable]:
if not AUTH_RATE_LIMITING_ENABLED:
return []
return [
Depends(
RateLimiter(
times=RATE_LIMIT_MAX_REQUESTS or 100,
seconds=RATE_LIMIT_WINDOW_SECONDS or 60,
# Use the custom key function to distinguish users
identifier=rate_limit_key,
)
)
]