| Crates.io | hotswap-config |
| lib.rs | hotswap-config |
| version | 0.1.1 |
| created_at | 2025-11-02 02:20:13.670155+00 |
| updated_at | 2025-11-02 03:14:39.552766+00 |
| description | Zero-downtime configuration management with lock-free hot-reloads and atomic updates |
| homepage | |
| repository | https://github.com/danielrcurtis/hotswap-config |
| max_upload_size | |
| id | 1912597 |
| size | 385,228 |
A high-performance, hot-reloadable configuration store with wait-free reads and transactional updates for Rust applications.
ArcSwap pattern) - readers never blocknotify crate) with automatic reloadpartial-updates)rollback)gradual-rollout)remote)metrics)Test System: Apple MacBook Pro (M3 Pro, 12-core, 18GB unified memory), macOS 26.0.1, Rust 1.87.0
Build: cargo bench --release (LTO=true, opt-level=3, codegen-units=1)
Methodology: Criterion 0.5, 100 samples, warm L3 cache
| Metric | Result | Notes |
|---|---|---|
| Read latency (median) | 7.16 ns/read | Single-threaded, warm cache |
| Read latency (mean) | 7.43 ns/read | Sub-10ns target achieved |
| Throughput (1 thread) | 206M reads/sec | = 206 million operations/sec |
| Throughput (16 threads) | 229M reads/sec total | = 14.4M reads/sec/thread |
| Config clone | 7.86 ns | Cheap Arc clone |
| Reload under load | 0 dropped reads | Zero downtime validated |
Readers are wait-free:
ArcSwap::load()is a single atomic read. Writers build new config off-to-the-side, validate, then atomically swap. Old readers continue using the previousArcuntil dropped.
See benches/README.md for full methodology, CPU governor settings, and raw criterion reports.
Add to Cargo.toml:
[dependencies]
hotswap-config = "0.1"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
10-line working example:
use hotswap_config::prelude::*;
use serde::Deserialize;
#[derive(Debug, Deserialize, Clone)]
struct AppConfig {
server_port: u16,
feature_flag: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
// Load config with file watching (auto-reloads on change)
let config = HotswapConfig::builder()
.with_file("config/default.yaml")
.with_env_overrides("APP", "__") // APP_SERVER_PORT=8080 overrides file
.with_validation(|cfg: &AppConfig| {
if cfg.server_port < 1024 {
return Err(ValidationError::invalid_field("server_port", "must be >= 1024"));
}
Ok(())
})
.build::<AppConfig>()
.await?;
// Wait-free reads (no locks!)
let cfg = config.get(); // Returns Arc<AppConfig>
println!("Server starting on port {}", cfg.server_port);
// Subscribe to changes
let _subscription = config.subscribe(|new_cfg| {
println!("Config reloaded! Feature flag: {}", new_cfg.feature_flag);
});
// Config automatically reloads when config/default.yaml changes
// Invalid configs are rejected; old config stays active
Ok(())
}
With partial updates (JSON Patch):
// Feature: partial-updates
config.update_field("/feature_flag", true).await?; // Atomic update with validation
| Feature | Description | Dependencies |
|---|---|---|
file-watch |
Auto-reload on file changes (default) | notify, tokio |
validation |
Config validation trait (default) | - |
yaml |
YAML file format support | serde_yaml |
toml |
TOML file format support | toml |
json |
JSON file format support | serde_json |
all-formats |
Enable all formats | - |
partial-updates |
JSON Patch (RFC 6902) | json-patch, tokio |
rollback |
Version history & rollback | chrono, tokio |
gradual-rollout |
A/B testing & canary | fastrand, tokio |
remote |
HTTP(S) config sources | reqwest, tokio |
metrics |
OpenTelemetry metrics | opentelemetry |
Default features: file-watch, validation
Enable features in Cargo.toml:
[dependencies]
hotswap-config = { version = "0.1", features = ["partial-updates", "rollback", "yaml"] }
Config sources are merged by priority (highest wins):
APP_SERVER__PORT=8080config/production.yamlconfig/default.yamlyamltomljsonFormat detected automatically by file extension.
Fn(&T) -> Result<(), ValidationError>)remote)rustls, native-certs)notify crate (inotify/kqueue/FSEvents)reload() still worksproptest for validation logicexamples/ directory with full scenarios# All tests with all features
cargo test --all-features
# Specific feature combinations
cargo test --features yaml,validation
cargo test --features "partial-updates,rollback"
# No default features
cargo test --no-default-features
# Service configuration (comprehensive example with validation)
cargo run --example service_config --features yaml
# Hot reload demonstration
cargo run --example hot_reload --features yaml
# Subscriber notifications
cargo run --example subscribers --features yaml
# Partial updates
cargo run --example partial_updates --features "yaml,partial-updates"
# Rollback demonstration
cargo run --example rollback --features "yaml,rollback"
# Gradual rollout
cargo run --example gradual_rollout --features "yaml,gradual-rollout"
# Remote HTTP source
cargo run --example remote_config --features "remote,yaml"
examples/ directoryDESIGN.mdCONTRIBUTING.mdCHANGELOG.md| Feature | hotswap-config | config | figment | confy |
|---|---|---|---|---|
| Wait-free reads | ✅ (ArcSwap) | ❌ | ❌ | ❌ |
| Hot reload | ✅ | ❌ | ❌ | ❌ |
| File watching | ✅ | ❌ | ❌ | ❌ |
| Validation | ✅ | Limited | ✅ | ❌ |
| Atomic updates | ✅ | ❌ | ❌ | ❌ |
| Rollback | ✅ | ❌ | ❌ | ❌ |
| Partial updates | ✅ | ❌ | ❌ | ❌ |
| Remote sources | ✅ | ❌ | Limited | ❌ |
| Metrics | ✅ | ❌ | ❌ | ❌ |
| Type-safe | ✅ | ✅ | ✅ | ✅ |
notify crate)std::sync::Arc, tokio runtime)Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
arc-swap crate for lock-free atomic updatesconfig cratenotify crateStatus: v0.1.0 - Production-ready, API stable
Built with ❤️ by Daniel Curtis