use std::collections::HashMap; use std::sync::atomic::AtomicU64; use std::sync::Arc; use std::sync::Mutex as StdMutex; use std::time::{Duration, Instant}; use aether_data::repository::users::StoredUserGroup; use aether_data_contracts::repository::billing::UserDailyQuotaAvailabilityRecord; use aether_data_contracts::repository::quota::StoredProviderQuotaSnapshot; use aether_data_contracts::repository::usage::UsageCounterHealthSnapshot; use aether_gateway_frontdoor::HttpConnectionBudget; use aether_runtime::ConcurrencyGate; use aether_runtime_state::{RuntimeSemaphore, RuntimeState}; use dashmap::DashMap; use tokio::sync::{Mutex as TokioMutex, RwLock as TokioRwLock, Semaphore}; use super::super::async_task::{VideoTaskPollerConfig, VideoTaskService}; use super::super::cache::{ AuthApiKeyFeatureCacheKey, AuthApiKeyIdentityCacheKey, AuthApiKeyLastUsedCache, AuthContextCache, AuthSnapshotCache, DashboardResponseCache, DirectPlanBypassCache, JsonValueCache, SchedulerAffinityCache, SystemConfigCache, ValueCache, }; use super::super::data::GatewayDataState; use super::super::fallback_metrics; use super::super::maintenance::UsageCounterFlushRuntimeMetrics; use super::super::rate_limit::FrontdoorUserRpmLimiter; use super::super::request_candidate_queue::RequestCandidateQueueRuntime; use super::super::task_runtime::TaskSupervisorMetrics; use super::super::{provider_transport, usage}; use super::{ AdminBillingCollectorRecord, AdminBillingRuleRecord, AdminPaymentCallbackRecord, AdminWalletPaymentOrderRecord, AdminWalletRefundRecord, AdminWalletTransactionRecord, CachedProviderTransportSnapshot, FrontdoorCorsConfig, LocalExecutionRuntimeMissDiagnostic, LocalProviderDeleteTaskState, ProviderTransportSnapshotCacheKey, ProviderTransportSnapshotFlight, }; const MIN_REQUEST_BODY_READ_TIMEOUT_MS: u64 = 1_000; const DEFAULT_REQUEST_BODY_READ_TIMEOUT_MS: u64 = 120_000; const MAX_REQUEST_BODY_READ_TIMEOUT_MS: u64 = 600_000; const REQUEST_BODY_READ_TIMEOUT_MS_ENV: &str = "AETHER_GATEWAY_REQUEST_BODY_READ_TIMEOUT_MS"; const DEFAULT_REQUEST_BODY_BUFFER_BUDGET_MB: usize = 256; const MIN_REQUEST_BODY_BUFFER_BUDGET_MB: usize = 64; const MAX_REQUEST_BODY_BUFFER_BUDGET_MB: usize = 16 * 1024; const REQUEST_BODY_BUFFER_BUDGET_MB_ENV: &str = "AETHER_GATEWAY_REQUEST_BODY_BUFFER_BUDGET_MB"; pub(crate) const REQUEST_BODY_BUFFER_PERMIT_BYTES: usize = 64 * 1024; const DEFAULT_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS: u64 = 30_000; const MIN_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS: u64 = 500; const MAX_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS: u64 = 120_000; const LOCAL_EXECUTION_PLANNING_TIMEOUT_MS_ENV: &str = "AETHER_GATEWAY_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS"; const DEFAULT_AUTH_SNAPSHOT_LOAD_GATE_LIMIT: usize = 64; const DEFAULT_CANDIDATE_PLANNING_GATE_LIMIT: usize = 1024; const DEFAULT_UPSTREAM_EXECUTION_GATE_LIMIT: usize = 10_000; const DEFAULT_UPSTREAM_TARGET_GATE_LIMIT: usize = 10_000; const MAX_AUTH_SNAPSHOT_LOAD_GATE_LIMIT: usize = 1024; const MAX_CANDIDATE_PLANNING_GATE_LIMIT: usize = 8192; const MAX_UPSTREAM_EXECUTION_GATE_LIMIT: usize = 32_768; const MAX_UPSTREAM_TARGET_GATE_LIMIT: usize = 32_768; const AUTH_SNAPSHOT_LOAD_GATE_LIMIT_PER_CPU: usize = 16; const CANDIDATE_PLANNING_GATE_LIMIT_PER_CPU: usize = 256; const UPSTREAM_EXECUTION_GATE_LIMIT_PER_CPU: usize = 1024; const UPSTREAM_TARGET_GATE_LIMIT_PER_CPU: usize = 1024; const GATE_LIMIT_FD_RESERVE: usize = 128; const DEFAULT_INTERNAL_GATE_QUEUE_BUDGET_MS: u64 = 250; const MAX_INTERNAL_GATE_QUEUE_BUDGET_MS: u64 = 5_000; const AUTH_SNAPSHOT_LOAD_GATE_LIMIT_ENV: &str = "AETHER_GATEWAY_AUTH_SNAPSHOT_LOAD_GATE_LIMIT"; const CANDIDATE_PLANNING_GATE_LIMIT_ENV: &str = "AETHER_GATEWAY_CANDIDATE_PLANNING_GATE_LIMIT"; const UPSTREAM_EXECUTION_GATE_LIMIT_ENV: &str = "AETHER_GATEWAY_UPSTREAM_EXECUTION_GATE_LIMIT"; const UPSTREAM_TARGET_GATE_LIMIT_ENV: &str = "AETHER_GATEWAY_UPSTREAM_TARGET_GATE_LIMIT"; const INTERNAL_GATE_QUEUE_BUDGET_MS_ENV: &str = "AETHER_GATEWAY_INTERNAL_GATE_QUEUE_BUDGET_MS"; const DEFAULT_AUTH_CAPACITY_CACHE_TTL_MS: u64 = 500; const MIN_AUTH_CAPACITY_CACHE_TTL_MS: u64 = 10; const MAX_AUTH_CAPACITY_CACHE_TTL_MS: u64 = 10_000; const AUTH_CAPACITY_CACHE_TTL_MS_ENV: &str = "AETHER_GATEWAY_AUTH_CAPACITY_CACHE_TTL_MS"; #[cfg(test)] type TestExecutionRuntimeSyncOverrideFn = dyn Fn( &aether_contracts::ExecutionPlan, ) -> Result + Send + Sync; #[cfg(test)] #[derive(Clone)] pub(crate) struct TestExecutionRuntimeSyncOverride( pub(crate) Arc, ); #[cfg(test)] impl std::fmt::Debug for TestExecutionRuntimeSyncOverride { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("TestExecutionRuntimeSyncOverride(..)") } } #[derive(Debug, Clone)] pub(crate) struct FrontdoorRuntimeGuardConfig { pub(crate) request_body_read_timeout: Option, pub(crate) request_body_buffer_budget_bytes: usize, pub(crate) request_body_buffer_budget_permits: usize, pub(crate) local_execution_planning_timeout: Duration, pub(crate) internal_gate_queue_budget: Duration, pub(crate) auth_capacity_cache_ttl: Duration, pub(crate) auth_snapshot_load_gate_limit: Option, pub(crate) candidate_planning_gate_limit: Option, pub(crate) upstream_execution_gate_limit: Option, pub(crate) upstream_target_gate_limit: Option, } pub(crate) const METRIC_SNAPSHOT_TTL: Duration = Duration::from_secs(2); impl FrontdoorRuntimeGuardConfig { pub(crate) fn from_env() -> Self { Self { request_body_read_timeout: optional_env_duration_ms( REQUEST_BODY_READ_TIMEOUT_MS_ENV, MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), request_body_buffer_budget_bytes: request_body_buffer_budget_bytes_from_env(), request_body_buffer_budget_permits: request_body_buffer_budget_permits_from_env(), local_execution_planning_timeout: env_duration_ms( LOCAL_EXECUTION_PLANNING_TIMEOUT_MS_ENV, DEFAULT_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS, MIN_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS, MAX_LOCAL_EXECUTION_PLANNING_TIMEOUT_MS, ), internal_gate_queue_budget: env_duration_ms( INTERNAL_GATE_QUEUE_BUDGET_MS_ENV, DEFAULT_INTERNAL_GATE_QUEUE_BUDGET_MS, 1, MAX_INTERNAL_GATE_QUEUE_BUDGET_MS, ), auth_capacity_cache_ttl: env_cache_duration_ms( AUTH_CAPACITY_CACHE_TTL_MS_ENV, DEFAULT_AUTH_CAPACITY_CACHE_TTL_MS, MIN_AUTH_CAPACITY_CACHE_TTL_MS, MAX_AUTH_CAPACITY_CACHE_TTL_MS, ), auth_snapshot_load_gate_limit: auth_snapshot_load_gate_limit_from_env(), candidate_planning_gate_limit: candidate_planning_gate_limit_from_env(), upstream_execution_gate_limit: upstream_execution_gate_limit_from_env(), upstream_target_gate_limit: upstream_target_gate_limit_from_env(), } } #[cfg(test)] pub(crate) fn for_tests( request_body_read_timeout: Option, local_execution_planning_timeout: Duration, ) -> Self { Self { request_body_read_timeout, request_body_buffer_budget_bytes: DEFAULT_REQUEST_BODY_BUFFER_BUDGET_MB * 1024 * 1024, request_body_buffer_budget_permits: DEFAULT_REQUEST_BODY_BUFFER_BUDGET_MB * 16, local_execution_planning_timeout, internal_gate_queue_budget: Duration::from_millis( DEFAULT_INTERNAL_GATE_QUEUE_BUDGET_MS, ), auth_capacity_cache_ttl: Duration::from_millis(DEFAULT_AUTH_CAPACITY_CACHE_TTL_MS), auth_snapshot_load_gate_limit: Some(DEFAULT_AUTH_SNAPSHOT_LOAD_GATE_LIMIT), candidate_planning_gate_limit: Some(DEFAULT_CANDIDATE_PLANNING_GATE_LIMIT), upstream_execution_gate_limit: Some(DEFAULT_UPSTREAM_EXECUTION_GATE_LIMIT), upstream_target_gate_limit: Some(DEFAULT_UPSTREAM_TARGET_GATE_LIMIT), } } } fn request_body_buffer_budget_mb_from_env() -> usize { std::env::var(REQUEST_BODY_BUFFER_BUDGET_MB_ENV) .ok() .and_then(|value| value.trim().parse::().ok()) .filter(|value| *value > 0) .unwrap_or(DEFAULT_REQUEST_BODY_BUFFER_BUDGET_MB) .clamp( MIN_REQUEST_BODY_BUFFER_BUDGET_MB, MAX_REQUEST_BODY_BUFFER_BUDGET_MB, ) } fn request_body_buffer_budget_bytes_from_env() -> usize { request_body_buffer_budget_mb_from_env().saturating_mul(1024 * 1024) } fn request_body_buffer_budget_permits_from_env() -> usize { request_body_buffer_budget_bytes_from_env().saturating_add(REQUEST_BODY_BUFFER_PERMIT_BYTES - 1) / REQUEST_BODY_BUFFER_PERMIT_BYTES } fn optional_env_duration_ms(key: &str, min_ms: u64, max_ms: u64) -> Option { let raw = std::env::var(key).ok(); parse_optional_duration_ms(raw.as_deref(), min_ms, max_ms) } fn parse_optional_duration_ms(raw: Option<&str>, min_ms: u64, max_ms: u64) -> Option { let parsed = raw .and_then(|value| value.trim().parse::().ok()) .unwrap_or(DEFAULT_REQUEST_BODY_READ_TIMEOUT_MS); if parsed == 0 { return None; } Some(Duration::from_millis(parsed.clamp(min_ms, max_ms))) } fn env_duration_ms(key: &str, default_ms: u64, min_ms: u64, max_ms: u64) -> Duration { let ms = std::env::var(key) .ok() .and_then(|value| value.trim().parse::().ok()) .filter(|value| *value > 0) .unwrap_or(default_ms) .clamp(min_ms, max_ms); Duration::from_millis(ms) } fn env_cache_duration_ms(key: &str, default_ms: u64, min_ms: u64, max_ms: u64) -> Duration { let Some(raw) = std::env::var(key) .ok() .map(|value| value.trim().to_string()) .filter(|value| !value.is_empty()) else { return Duration::from_millis(default_ms); }; let Some(parsed) = raw.parse::().ok() else { return Duration::from_millis(default_ms); }; if parsed == 0 { return Duration::ZERO; } Duration::from_millis(parsed.clamp(min_ms, max_ms)) } #[derive(Debug, Clone, Copy)] struct GateAutoProfile { floor: usize, cap: usize, per_cpu: usize, fd_divisor: Option, } #[derive(Debug, Clone, Copy)] struct GateAutoCapacity { cpu_parallelism: usize, fd_soft_limit: usize, } const CANDIDATE_PLANNING_GATE_AUTO_PROFILE: GateAutoProfile = GateAutoProfile { floor: DEFAULT_CANDIDATE_PLANNING_GATE_LIMIT, cap: MAX_CANDIDATE_PLANNING_GATE_LIMIT, per_cpu: CANDIDATE_PLANNING_GATE_LIMIT_PER_CPU, fd_divisor: None, }; const AUTH_SNAPSHOT_LOAD_GATE_AUTO_PROFILE: GateAutoProfile = GateAutoProfile { floor: DEFAULT_AUTH_SNAPSHOT_LOAD_GATE_LIMIT, cap: MAX_AUTH_SNAPSHOT_LOAD_GATE_LIMIT, per_cpu: AUTH_SNAPSHOT_LOAD_GATE_LIMIT_PER_CPU, fd_divisor: None, }; const UPSTREAM_EXECUTION_GATE_AUTO_PROFILE: GateAutoProfile = GateAutoProfile { floor: DEFAULT_UPSTREAM_EXECUTION_GATE_LIMIT, cap: MAX_UPSTREAM_EXECUTION_GATE_LIMIT, per_cpu: UPSTREAM_EXECUTION_GATE_LIMIT_PER_CPU, fd_divisor: Some(2), }; const UPSTREAM_TARGET_GATE_AUTO_PROFILE: GateAutoProfile = GateAutoProfile { floor: DEFAULT_UPSTREAM_TARGET_GATE_LIMIT, cap: MAX_UPSTREAM_TARGET_GATE_LIMIT, per_cpu: UPSTREAM_TARGET_GATE_LIMIT_PER_CPU, fd_divisor: Some(4), }; fn candidate_planning_gate_limit_from_env() -> Option { env_gate_limit( CANDIDATE_PLANNING_GATE_LIMIT_ENV, CANDIDATE_PLANNING_GATE_AUTO_PROFILE, ) } fn auth_snapshot_load_gate_limit_from_env() -> Option { env_gate_limit( AUTH_SNAPSHOT_LOAD_GATE_LIMIT_ENV, AUTH_SNAPSHOT_LOAD_GATE_AUTO_PROFILE, ) } fn upstream_execution_gate_limit_from_env() -> Option { env_gate_limit( UPSTREAM_EXECUTION_GATE_LIMIT_ENV, UPSTREAM_EXECUTION_GATE_AUTO_PROFILE, ) } pub(crate) fn upstream_target_gate_limit_from_env() -> Option { env_gate_limit( UPSTREAM_TARGET_GATE_LIMIT_ENV, UPSTREAM_TARGET_GATE_AUTO_PROFILE, ) } pub(crate) fn upstream_target_gate_auto_limit() -> usize { auto_gate_limit( UPSTREAM_TARGET_GATE_AUTO_PROFILE, current_gate_auto_capacity(), ) } fn env_gate_limit(key: &str, profile: GateAutoProfile) -> Option { let raw = std::env::var(key).ok(); parse_gate_limit_value(raw.as_deref(), profile, current_gate_auto_capacity()) } fn parse_gate_limit_value( raw: Option<&str>, profile: GateAutoProfile, capacity: GateAutoCapacity, ) -> Option { let Some(value) = raw.map(str::trim).filter(|value| !value.is_empty()) else { return Some(auto_gate_limit(profile, capacity)); }; let normalized = value.to_ascii_lowercase(); match normalized.as_str() { "auto" => Some(auto_gate_limit(profile, capacity)), "off" | "none" | "disabled" | "disable" => None, _ => match value.parse::() { Ok(0) => None, Ok(limit) => Some(limit.max(1)), Err(_) => Some(auto_gate_limit(profile, capacity)), }, } } fn auto_gate_limit(profile: GateAutoProfile, capacity: GateAutoCapacity) -> usize { let cpu_limit = capacity .cpu_parallelism .max(1) .saturating_mul(profile.per_cpu.max(1)); let mut limit = cpu_limit.max(profile.floor).min(profile.cap); if let Some(fd_divisor) = profile.fd_divisor.filter(|value| *value > 0) { let fd_budget = capacity .fd_soft_limit .saturating_sub(GATE_LIMIT_FD_RESERVE) .checked_div(fd_divisor) .unwrap_or(1) .max(1); limit = limit.min(fd_budget); } limit.max(1) } fn current_gate_auto_capacity() -> GateAutoCapacity { GateAutoCapacity { cpu_parallelism: std::thread::available_parallelism() .map(|value| value.get()) .unwrap_or(1) .max(1), fd_soft_limit: soft_fd_limit().unwrap_or(1024).max(1), } } fn soft_fd_limit() -> Option { #[cfg(unix)] { let mut limit = libc::rlimit { rlim_cur: 0, rlim_max: 0, }; let result = unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut limit) }; if result == 0 { return usize::try_from(limit.rlim_cur).ok(); } } None } #[derive(Debug, Clone)] pub struct AppState { #[cfg(test)] pub(crate) execution_runtime_override_base_url: Option, #[cfg(test)] pub(crate) execution_runtime_sync_override: Option, pub(crate) data: Arc, pub(crate) background_data: Arc, pub(crate) background_data_isolated: bool, pub(crate) runtime_state: Arc, pub(crate) internal_gateway_auth: Arc, pub(crate) usage_runtime: Arc, pub(crate) video_tasks: Arc, pub(crate) video_task_poller: Option, pub(crate) frontdoor_runtime_guards: Arc, pub(crate) request_body_buffer_budget: Arc, pub(crate) http_connection_budget: Option>, pub(crate) request_gate: Option>, pub(crate) websocket_connection_gate: Option>, pub(crate) auth_snapshot_load_gate: Option>, pub(crate) candidate_planning_gate: Option>, pub(crate) upstream_execution_gate: Option>, pub(crate) upstream_target_admission: Arc, pub(crate) distributed_request_gate: Option>, pub(crate) distributed_websocket_connection_gate: Option>, pub(crate) client: reqwest::Client, pub(crate) owner_forward_client: reqwest::Client, pub(crate) auth_context_cache: Arc, pub(crate) auth_snapshot_cache: Arc, pub(crate) admin_security_blacklist_cache: Arc>, pub(crate) admin_security_whitelist_cache: Arc>>, pub(crate) user_model_capability_settings_cache: Arc>, pub(crate) user_feature_settings_cache: Arc>, pub(crate) auth_api_key_force_capabilities_cache: Arc>, pub(crate) auth_api_key_feature_settings_cache: Arc>, pub(crate) auth_daily_quota_availability_cache: Arc>, pub(crate) auth_plan_usage_policy_cache: Arc>, pub(crate) auth_wallet_snapshot_cache: Arc>, pub(crate) auth_request_cost_upper_bound_cache: Arc>, pub(crate) provider_quota_snapshot_cache: Arc>, pub(crate) user_groups_for_user_cache: Arc>>, pub(crate) routing_group_selection_cache: Arc>, pub(crate) auth_api_key_last_used_cache: Arc, pub(crate) oauth_refresh: Arc, pub(crate) direct_plan_bypass_cache: Arc, pub(crate) scheduler_affinity_cache: Arc, pub(crate) scheduler_affinity_epoch: Arc, pub(crate) dashboard_response_cache: Arc, pub(crate) system_config_cache: Arc, pub(crate) endpoint_response_header_rules_cache: Arc>, pub(crate) candidate_row_page_cache: Arc, pub(crate) candidate_page_cache: Arc, pub(crate) candidate_resolved_page_cache: Arc, pub(crate) chat_pii_redaction_runtime_config_cache: crate::privacy::ChatPiiRedactionRuntimeConfigCacheHandle, pub(crate) fallback_metrics: Arc, pub(crate) usage_counter_flush_metrics: Arc, pub(crate) task_supervisor_metrics: TaskSupervisorMetrics, pub(crate) process_resource_monitor: Arc, pub(crate) metric_snapshot: Arc)>>>, pub(crate) metric_snapshot_refresh: Arc>, pub(crate) usage_counter_exact_health_metric_snapshot: Arc>>, pub(crate) usage_counter_exact_health_metric_last_attempt: Arc>>, pub(crate) usage_counter_exact_health_metric_refresh: Arc>, pub(crate) request_candidate_queue: Option>, pub(crate) frontdoor_cors: Option>, pub(crate) frontdoor_user_rpm: Arc, pub(crate) tunnel: crate::tunnel::EmbeddedTunnelState, pub(crate) provider_transport_snapshot_cache: Arc>, pub(crate) provider_transport_snapshot_cache_generation: Arc, pub(crate) provider_transport_snapshot_inflight: Arc>>, pub(crate) provider_key_rpm_resets: Arc>>, pub(crate) local_execution_runtime_miss_diagnostics: Arc>, pub(crate) admin_monitoring_error_stats_reset_at: Arc>>, pub(crate) provider_delete_tasks: Arc>>, pub(crate) pool_quota_probe_replenish: Arc, #[cfg(test)] pub(crate) turnstile_siteverify_url_override: Option, #[cfg(test)] pub(crate) turnstile_siteverify_timeout_override: Option, #[cfg(test)] pub(crate) provider_oauth_state_store: Option>>>, #[cfg(test)] pub(crate) provider_oauth_device_session_store: Option>>>, #[cfg(test)] pub(crate) provider_oauth_batch_task_store: Option>>>, #[cfg(test)] pub(crate) auth_session_store: Option>>>, #[cfg(test)] pub(crate) auth_email_verification_store: Option>>>, #[cfg(test)] pub(crate) auth_email_delivery_store: Option>>>, #[cfg(test)] pub(crate) auth_user_store: Option< Arc>>, >, #[cfg(test)] pub(crate) auth_user_model_capability_store: Option>>>, #[cfg(test)] pub(crate) auth_wallet_store: Option< Arc>>, >, #[cfg(test)] pub(crate) admin_wallet_payment_order_store: Option>>>, #[cfg(test)] pub(crate) admin_payment_callback_store: Option>>>, #[cfg(test)] pub(crate) admin_wallet_transaction_store: Option>>>, #[cfg(test)] pub(crate) admin_wallet_refund_store: Option>>>, #[cfg(test)] pub(crate) admin_billing_rule_store: Option>>>, #[cfg(test)] pub(crate) admin_billing_collector_store: Option>>>, #[cfg(test)] pub(crate) admin_security_blacklist_store: Option>>>, #[cfg(test)] pub(crate) admin_security_whitelist_store: Option>>>, #[cfg(test)] pub(crate) admin_monitoring_cache_affinity_store: Option>>>, #[cfg(test)] pub(crate) admin_monitoring_redis_key_store: Option>>>, #[cfg(test)] pub(crate) provider_oauth_token_url_overrides: Arc>>, } #[cfg(test)] mod tests { use super::*; const TEST_PROFILE: GateAutoProfile = GateAutoProfile { floor: 10_000, cap: 16_384, per_cpu: 1024, fd_divisor: Some(2), }; const TEST_CAPACITY: GateAutoCapacity = GateAutoCapacity { cpu_parallelism: 12, fd_soft_limit: 1_048_576, }; #[test] fn request_body_read_timeout_parser_uses_a_finite_default() { for value in [None, Some(""), Some("invalid"), Some("-1")] { assert_eq!( parse_optional_duration_ms( value, MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), Some(Duration::from_millis(DEFAULT_REQUEST_BODY_READ_TIMEOUT_MS)), ); } } #[test] fn request_body_read_timeout_parser_only_disables_explicit_zero() { for value in ["0", " 0 "] { assert_eq!( parse_optional_duration_ms( Some(value), MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), None, "{value:?} should disable the optional timeout" ); } } #[test] fn request_body_read_timeout_parser_clamps_nonzero_values() { assert_eq!( parse_optional_duration_ms( Some("1"), MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), Some(Duration::from_millis(MIN_REQUEST_BODY_READ_TIMEOUT_MS)) ); assert_eq!( parse_optional_duration_ms( Some("120000"), MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), Some(Duration::from_millis(120_000)) ); assert_eq!( parse_optional_duration_ms( Some("900000"), MIN_REQUEST_BODY_READ_TIMEOUT_MS, MAX_REQUEST_BODY_READ_TIMEOUT_MS, ), Some(Duration::from_millis(MAX_REQUEST_BODY_READ_TIMEOUT_MS)) ); } #[test] fn gate_limit_parser_defaults_to_auto() { assert_eq!( parse_gate_limit_value(None, TEST_PROFILE, TEST_CAPACITY), Some(12_288) ); assert_eq!( parse_gate_limit_value(Some("auto"), TEST_PROFILE, TEST_CAPACITY), Some(12_288) ); assert_eq!( parse_gate_limit_value(Some(" AUTO "), TEST_PROFILE, TEST_CAPACITY), Some(12_288) ); } #[test] fn auth_snapshot_load_gate_auto_limit_uses_smaller_frontdoor_profile() { assert_eq!( parse_gate_limit_value( Some("auto"), AUTH_SNAPSHOT_LOAD_GATE_AUTO_PROFILE, TEST_CAPACITY ), Some(192) ); } #[test] fn gate_limit_parser_accepts_fixed_numbers() { assert_eq!( parse_gate_limit_value(Some("4096"), TEST_PROFILE, TEST_CAPACITY), Some(4096) ); assert_eq!( parse_gate_limit_value( Some("20000"), UPSTREAM_TARGET_GATE_AUTO_PROFILE, TEST_CAPACITY ), Some(20_000) ); assert_eq!( parse_gate_limit_value( Some("20000"), UPSTREAM_EXECUTION_GATE_AUTO_PROFILE, TEST_CAPACITY ), Some(20_000) ); } #[test] fn gate_limit_parser_accepts_off_and_legacy_zero() { for value in ["off", "none", "disabled", "disable", "0"] { assert_eq!( parse_gate_limit_value(Some(value), TEST_PROFILE, TEST_CAPACITY), None ); } } #[test] fn auto_gate_limit_respects_fd_budget_when_fd_limit_is_low() { assert_eq!( parse_gate_limit_value( Some("auto"), TEST_PROFILE, GateAutoCapacity { cpu_parallelism: 32, fd_soft_limit: 1024, }, ), Some(448) ); } }