Expand description
Replacing a running configuration without restarting the process.
serve_on_with builds everything exactly once — profiles, deduplicated
signer backends, filter chains, challenge registries, both routers — so until
this module existed, every configuration change was a process restart. For
the keys operators actually touch (a [filter] rule, an [ipam] token, a
[notify] webhook, a renewed certificate) that dropped in-flight ACME orders
and every live connection for a change that never needed a new socket.
A reload is a rebuild and swap, not a mutation. Everything is constructed
and validated first; only once all of it succeeded is anything published. The
publishing itself goes through tokio::sync::watch cells, and that choice
is load-bearing rather than stylistic: watch::Sender::send_replace is
synchronous, so a run of sends with no .await between them cannot be
observed half-applied — no other task can run in the middle of it.
What a swap cannot honour is refused by name, and the whole reload is
refused with it. Exactly one key is left in that category — database.url,
the pool being open and the accounts and orders issued against it not
following a URL elsewhere. Refusing by name is the posture startup already
takes when it rejects an unknown logging.target rather than falling back.
Everything else that used to be on that list came off the same way — the thing said to be unmovable was made movable rather than argued with:
[logging], the tracing subscriber being installed once per process.server::loggingnow installs the whole stack behind atracing_subscriber::reload::Layer, so all six keys swap with everything else. The publishing run does it first, since an operator who raised the level did it to see what happens next — starting with the reload’s own line.- The sockets.
acme_proxy_net::listenerowns the accept loop, so a role’sTcpListeneris replaceable and its TLS mode is read per connection: all five ofserver.bind_address,admin.enabled,admin.bind_addressand bothtls.enabledflips reload, as do the two[metrics]keys. Binding happens while a failure can still refuse the reload, so a bad address is answered by a socket that never moved. [jobs], the runner having snapshotted its pacing at spawn. It now re-derives that pacing from awatchcell on every pass of its loop and resizes its own concurrency pool, and the queue readsmax_attemptsfrom a shared atomic — so all seven keys reload, and none of them was ever physically frozen the way the pool is. These are the knobs an operator reaches for mid-incident (slow a retry storm, widen a lease, raise concurrency), which made them the worst possible thing to charge a restart for. Seeacme_proxy_jobs::jobs::runner.- The profile set, each profile’s
[signer], and[dns]/[proxy]— the last four and the hardest, because a signer backend used to own state with no durable home: aLocalCa’s revocation ledger and a relay’shttp-01token store. Both now live in the database, which the outgoing and the incoming backend share, so a backend whose configuration moved is simply rebuilt — a revocation landing mid-reload is in the table the new instance reads, and a challenge fetch in flight is answered from the same rows. A backend whose configuration did not move is reused verbatim rather than rebuilt. Mounting and unmounting an endpoint fell out of it for free, that having been the whole of what made the profile set unmovable, and[dns]/[proxy]fell out too: they were frozen only because the signers cached them at construction, which is now a reason to rebuild a signer (they are part of its identity key) rather than to refuse the edit.
Structs§
- Applied
- One resolved configuration, as the frozen-key check sees it.
- Reload
Handle - The handle a signal handler (or a future admin route) triggers reloads with.
- Reload
Report - What a completed reload did.
- Reload
Request - One request to reload, and where to send the answer.
- Reloads
- The receiving half, held by the serving path.
Enums§
- Reload
Error - Why a reload did not happen.
Functions§
- channel
- Opens a reload channel.
- check_
frozen - Refuses
proposedby name if it changes anything [FROZEN] covers. - router_
channel - Opens a router cell, with
initialas its first generation. - swappable
- Wraps a router cell as one servable
Router.