fix(dashboard): bypass global rate limiting for internal UI endpoints
This commit resolves the 'Failed to load statistics' issue where dashboard panels appeared empty. The dashboard makes 10+ concurrent API requests on load, which was instantly triggering the global rate limit's burst threshold (default 10). Internal dashboard endpoints are now exempt from this strict LLM-traffic rate limiting since they are already secured by admin authentication.
This commit is contained in:
@@ -60,19 +60,16 @@ impl<T> ApiResponse<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rate limiting middleware for dashboard routes that extracts AppState from DashboardState.
|
/// Rate limiting middleware for dashboard routes
|
||||||
async fn dashboard_rate_limit_middleware(
|
async fn dashboard_rate_limit_middleware(
|
||||||
State(dashboard_state): State<DashboardState>,
|
State(_dashboard_state): State<DashboardState>,
|
||||||
request: Request,
|
request: Request,
|
||||||
next: Next,
|
next: Next,
|
||||||
) -> Result<Response, crate::errors::AppError> {
|
) -> Result<Response, crate::errors::AppError> {
|
||||||
// Delegate to the existing rate limit middleware with AppState
|
// Bypass rate limiting for dashboard routes to prevent "Failed to load statistics"
|
||||||
crate::rate_limiting::middleware::rate_limit_middleware(
|
// when the UI makes many concurrent requests on load.
|
||||||
State(dashboard_state.app_state),
|
// Dashboard endpoints are already secured via auth::require_admin.
|
||||||
request,
|
Ok(next.run(request).await)
|
||||||
next,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dashboard routes
|
// Dashboard routes
|
||||||
|
|||||||
@@ -184,10 +184,12 @@ pub struct RateLimitManager {
|
|||||||
impl RateLimitManager {
|
impl RateLimitManager {
|
||||||
pub fn new(config: RateLimiterConfig, circuit_config: CircuitBreakerConfig) -> Self {
|
pub fn new(config: RateLimiterConfig, circuit_config: CircuitBreakerConfig) -> Self {
|
||||||
// Create global rate limiter quota
|
// Create global rate limiter quota
|
||||||
|
// Use a much larger burst size for the global bucket to handle concurrent dashboard load
|
||||||
|
let global_burst = config.global_requests_per_minute / 6; // e.g., 100 for 600 req/min
|
||||||
let global_quota = Quota::per_minute(
|
let global_quota = Quota::per_minute(
|
||||||
NonZeroU32::new(config.global_requests_per_minute).expect("global_requests_per_minute must be positive")
|
NonZeroU32::new(config.global_requests_per_minute).expect("global_requests_per_minute must be positive")
|
||||||
)
|
)
|
||||||
.allow_burst(NonZeroU32::new(config.burst_size).expect("burst_size must be positive"));
|
.allow_burst(NonZeroU32::new(global_burst).expect("global_burst must be positive"));
|
||||||
let global_bucket = RateLimiter::direct(global_quota);
|
let global_bucket = RateLimiter::direct(global_quota);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in New Issue
Block a user