Expand description
One reading of each configuration section, taken when a request begins.
Config::current() is an atomic load, and its own documentation says to
call it once per request: a reload landing between two calls lets one
request observe two configurations. With one section that is easy to
honour. With two it is not, because “the same generation” is a property
of a pair of reads that no single call site can see.
This crate is the pair. A Sections list is read once into a
Snapshot, the framework adapter puts that snapshot where the request
can reach it, and every handler read comes back out of it.
use std::sync::Arc;
use dynamic_config_web_core::Sections;
#[derive(Debug, PartialEq)]
struct Server { port: u16 }
#[derive(Debug, PartialEq)]
struct Features { cache: bool }
let sections = Sections::new()
.section({ let it = Arc::clone(&server); move || Some(Arc::clone(&it)) })
.section({ let it = Arc::clone(&features); move || Some(Arc::clone(&it)) });
let snapshot = sections.take();
assert_eq!(snapshot.get::<Server>().unwrap().port, 8080);
assert!(snapshot.get::<Features>().unwrap().cache);In a service the closures are || ServerConfig::try_current(), which the
sections! macro writes for you.
§How one reading stays one reading
Each configuration has its own atomic cell and the engine keeps no epoch across them, so reading N sections is N independent loads — and a reload landing between two of them would put two generations in one snapshot, which is the bug this crate exists to prevent.
Sections::take therefore reads the install counters, reads the
sections, and reads the counters again; if anything moved it starts
over. A section registered through Sections::section supplies no
counter, and a list containing one reads without the check —
Sections::is_consistent says which kind you have, and the
sections! macro always produces the checked kind.
§Why closures rather than a trait
#[dynamic_config] writes try_current() as an inherent method, so a
generic function cannot call it. A closure can, and the same shape covers
a Dynamic<T> instance — move || handle.current() — which a trait
implemented on the type could not reach.
Macros§
- sections
- The sections a request reads, by type.
Structs§
- Sections
- The sections a request reads, and how to read each one.
- Snapshot
- What one request may read: one
Arcper section, taken together.
Enums§
- NotIn
Scope - Why a section is not in this request’s snapshot.