Implement DynamicConfig with ArcSwap hot-reload and ConfigReloadHandle
Add ConfigReloadHandle with Arc<ArcSwap<DynamicConfig>> for lock-free reads on the request hot path and tokio::sync::Mutex-serialized reload. Add static config change detection via diff_static_config(). Add DynamicConfig validation (rate_limit, body_limit, site checks). Add PartialEq derives to config types. Include unit tests for ArcSwap swap visibility, invalid config rejection, and concurrent reload serialization.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use super::dynamic_config::DynamicConfig;
|
||||
use super::static_config::StaticConfig;
|
||||
@@ -6,7 +6,61 @@ use super::static_config::StaticConfig;
|
||||
#[allow(dead_code)]
|
||||
pub fn validate_config(
|
||||
_static_config: &StaticConfig,
|
||||
_dynamic_config: &DynamicConfig,
|
||||
dynamic_config: &DynamicConfig,
|
||||
) -> Result<()> {
|
||||
if dynamic_config.rate_limit.requests_per_second == 0 {
|
||||
bail!("rate_limit.requests_per_second must be > 0");
|
||||
}
|
||||
if dynamic_config.rate_limit.burst == 0 {
|
||||
bail!("rate_limit.burst must be > 0");
|
||||
}
|
||||
if dynamic_config.body.limit_bytes == 0 {
|
||||
bail!("body.limit_bytes must be > 0");
|
||||
}
|
||||
for site in &dynamic_config.sites {
|
||||
if site.host.is_empty() {
|
||||
bail!("site host must not be empty");
|
||||
}
|
||||
if site.upstream.is_empty() {
|
||||
bail!("site upstream must not be empty");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::test_fixtures;
|
||||
|
||||
#[test]
|
||||
fn valid_config_passes_validation() {
|
||||
let static_config = test_fixtures::test_static_config();
|
||||
let dynamic_config = test_fixtures::test_dynamic_config();
|
||||
assert!(validate_config(&static_config, &dynamic_config).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_requests_per_second_fails() {
|
||||
let static_config = test_fixtures::test_static_config();
|
||||
let mut dynamic_config = test_fixtures::test_dynamic_config();
|
||||
dynamic_config.rate_limit.requests_per_second = 0;
|
||||
assert!(validate_config(&static_config, &dynamic_config).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_burst_fails() {
|
||||
let static_config = test_fixtures::test_static_config();
|
||||
let mut dynamic_config = test_fixtures::test_dynamic_config();
|
||||
dynamic_config.rate_limit.burst = 0;
|
||||
assert!(validate_config(&static_config, &dynamic_config).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_body_limit_fails() {
|
||||
let static_config = test_fixtures::test_static_config();
|
||||
let mut dynamic_config = test_fixtures::test_dynamic_config();
|
||||
dynamic_config.body.limit_bytes = 0;
|
||||
assert!(validate_config(&static_config, &dynamic_config).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user