cache: share ingress rate limits across instances

This commit is contained in:
a.tolmachev
2026-05-03 21:59:49 +00:00
parent 3256203876
commit d3b7d246da
6 changed files with 171 additions and 30 deletions
+10 -2
View File
@@ -22,7 +22,8 @@ use crate::{
state::AppState,
};
use crank_runtime::{
RequestRateLimitConfig, RequestRateLimiter, RuntimeExecutor, RuntimeLimits, SecretCrypto,
RequestRateLimitConfig, RequestRateLimiter, RuntimeCacheConfig, RuntimeCacheStores,
RuntimeExecutor, RuntimeLimits, SecretCrypto,
};
#[tokio::main]
@@ -61,6 +62,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
};
let runtime_limits = RuntimeLimits::from_env()?;
let cache_config = RuntimeCacheConfig::from_env()?;
let cache_stores = RuntimeCacheStores::from_config(&cache_config).await?;
let api_rate_limit = admin_api_rate_limit_config_from_env()?;
let secret_crypto = SecretCrypto::new(&env::var("CRANK_MASTER_KEY")?)?;
let runtime = RuntimeExecutor::with_limits(runtime_limits);
@@ -77,7 +80,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
let state = AppState {
service,
api_rate_limiter: RequestRateLimiter::new(api_rate_limit),
api_rate_limiter: if cache_config.backend.is_external() {
RequestRateLimiter::new_shared(api_rate_limit, cache_stores.rate_limit.clone())
} else {
RequestRateLimiter::new(api_rate_limit)
},
};
let app = build_app(state);
let listener = TcpListener::bind(socket_addr).await?;
@@ -89,6 +96,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
runtime_max_concurrent_jobs = runtime_limits.max_concurrent_jobs,
admin_rate_limit_rps = api_rate_limit.requests_per_second,
admin_rate_limit_burst = api_rate_limit.burst,
cache_backend = %cache_config.backend,
max_connections = pool_config.max_connections,
min_connections = pool_config.min_connections,
acquire_timeout_ms = pool_config.acquire_timeout_ms,
+1 -1
View File
@@ -14,7 +14,7 @@ pub async fn apply_api_rate_limit(
next: Next,
) -> Result<Response, ApiError> {
let key = rate_limit_key(request.headers(), request.uri().path());
if let Err(rejection) = state.api_rate_limiter.check(&key) {
if let Err(rejection) = state.api_rate_limiter.check(&key).await {
return Err(ApiError::rate_limited_with_context(
"request rate limit exceeded",
rejection_context(rejection),